0Pricing
Kotlin Academy · Lesson

Reading Annotations at Runtime

Retrieve annotation instances from declarations using Kotlin reflection.

Reading Annotations at Runtime is a free Kotlin Academy lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Prerequisites

To read annotations at runtime you need: (1) the annotation declared with @Retention(RUNTIME), (2) the kotlin-reflect dependency on the classpath, and (3) a KClass, KFunction, or KProperty reference to the annotated element.

Reading Annotations from a KClass

Call annotations on a KClass to get all annotations on that class, or use findAnnotation() for a specific type:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
annotation class Table(val name: String)

@Table(name = "users")
class UserEntity

val ann = UserEntity::class.findAnnotation<Table>()
println(ann?.name)  // "users"

Reading Annotations from Properties

Access annotations on properties via KProperty.annotations or findAnnotation():

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.PROPERTY)
annotation class Column(val name: String)

data class User(@Column("user_name") val name: String)

val prop = User::name
val col = prop.findAnnotation<Column>()
println(col?.name)  // "user_name"

Reading Annotations from Functions

Use KFunction.findAnnotation() to read annotations on functions:

@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
annotation class Transactional

class UserService {
    @Transactional
    fun save(user: User) { /*...*/ }
}

val fn = UserService::save
val isTx = fn.hasAnnotation<Transactional>()
println(isTx)  // true

Iterating All Properties for Annotations

A common pattern is to scan all declared properties of a class and collect those annotated with a specific annotation:

fun <A : Annotation> KClass<*>.annotatedProperties(
    annotationClass: KClass<A>
): List<Pair<KProperty1<*, *>, A>> =
    declaredMemberProperties
        .mapNotNull { prop ->
            prop.findAnnotation(annotationClass)?.let { ann -> prop to ann }
        }

Reading Annotations on Parameters

Access constructor parameter annotations via KFunction.parameters:

class Repo(
    @param:Validate(minLength = 3) val name: String
)

val ctor = Repo::class.primaryConstructor!!
val param = ctor.parameters.first()
val ann = param.findAnnotation<Validate>()
println(ann?.minLength)  // 3

hasAnnotation vs findAnnotation

Use hasAnnotation() for a boolean check; use findAnnotation() when you need the annotation's property values. Both are extension functions from kotlin.reflect.full.

Walking the Class Hierarchy

Annotations on superclasses or interfaces are NOT inherited automatically in Kotlin reflection. You must walk KClass.superclasses or use KClass.allSuperclasses if you need inherited annotations.

fun KClass<*>.findAnnotationRecursive(ann: KClass<out Annotation>) =
    generateSequence(this) { null } // simplified — real impl walks supers
        .flatMap { it.annotations }
        .firstOrNull { it.annotationClass == ann }

Performance

Reflection calls are slow. If you scan annotations at framework startup, cache the results in a map keyed by KClass. Never read annotations in per-request or per-frame hot paths.

use-site targets and JVM fields

For annotations on properties with @field: target, the annotation lives on the JVM backing field. Access it via Java reflection (KProperty.javaField?.annotations) instead of Kotlin's annotations list, which only covers the Kotlin declaration site.

Practical Example: Simple ORM Mapper

A tiny ORM mapper reads @Column annotations to build a SQL column list:

fun columns(klass: KClass<*>): String =
    klass.declaredMemberProperties
        .mapNotNull { it.findAnnotation<Column>()?.name }
        .joinToString(", ")

println(columns(User::class))  // "user_name, email"

Quick Check

How do you read a specific annotation of type MyAnn from a KClass?

Recap: Reading Annotations at Runtime

Key takeaways:

  • Annotation must have @Retention(RUNTIME)
  • Use findAnnotation() to get an annotation's value, hasAnnotation() for a boolean check
  • Works on KClass, KFunction, KProperty, and KParameter
  • Cache scan results at startup to avoid per-request overhead
  • For @field: annotations, use KProperty.javaField

Frequently asked questions

Is the “Reading Annotations at Runtime” lesson free?

Yes — the full text of “Reading Annotations at Runtime” is free to read here on the web, and the Kotlin Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Kotlin Academy course, upgrade to CoddyKit PRO.

What will I learn in “Reading Annotations at Runtime”?

Retrieve annotation instances from declarations using Kotlin reflection. You practise Kotlin Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Kotlin Academy?

No prior experience is required. Kotlin Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Reading Annotations at Runtime” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Kotlin Academy lesson?

Yes. Every Kotlin Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Kotlin Reflection: KClass, KFunction, KProperty
  2. Creating and Targeting Custom Annotations
  3. Reading Annotations at Runtime
  4. Reflection-Based Validation and Mapping
← Back to Kotlin Academy