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) // trueIterating 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) // 3hasAnnotation 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
findAnnotationto get an annotation's value,() hasAnnotationfor a boolean check() - Works on
KClass,KFunction,KProperty, andKParameter - Cache scan results at startup to avoid per-request overhead
- For
@field:annotations, useKProperty.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.