Kotlin Academy · Lesson

Reading Annotations at Runtime

Retrieve annotation instances from declarations using Kotlin reflection.

Lesson 3 of 413 steps

Reading Annotations at Runtime is a free Kotlin Academy lesson on CoddyKit. This is lesson 3 of 4. Any 3 lessons of this learning path are free to read in full — after that, CoddyKit PRO unlocks every lesson, plus hands-on practice with a built-in code editor and a 24/7 AI tutor. It is part of the Kotlin Academy learning path, and your progress syncs across the web and the CoddyKit app. The Kotlin Academy course includes 4 lessons in total.

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
Free to start

Learn Kotlin with an AI tutor — free

Write and run real code in your browser, get instant help from a 24/7 AI tutor, and pick up where you left off on the web or in the app.

Courses
51
Lessons
203

Frequently Asked Questions

Is the “Reading Annotations at Runtime” lesson free?

Yes — any 3 lessons of the Kotlin Academy learning path, including “Reading Annotations at Runtime”, are free to read in full here on the web. After that, CoddyKit PRO unlocks every lesson, plus interactive practice with a built-in code editor and a 24/7 AI tutor. The Kotlin Academy course includes 4 lessons in total.

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, so you can start here or from the beginning and move at your own pace. This is lesson 3 of 4.

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