skip to content

What do the @Retention and @Target meta-annotations control when you declare your own Kotlin annotation?

level: juniorimportance: must knowfreq 55%

answer

  1. Retention = how long it lives (SOURCE/BINARY/RUNTIME)
  2. Target = where it can go (CLASS/FUNCTION/PROPERTY/...)
  3. Default retention = RUNTIME
  4. Only RUNTIME is reflection-visible
  5. Wrong target = compile error

basics

~10 s

@Retention says how long the annotation is kept: source only, in the class file, or readable at runtime. @Target says where you can put it: on classes, functions, properties, parameters, and so on.

solid answer

~30 s

Both are meta-annotations (annotations applied to an annotation class). @Retention takes an AnnotationRetention enum value: SOURCE (discarded by the compiler), BINARY (kept in the .class file but not visible to reflection), or RUNTIME (kept and readable via Kotlin/Java reflection). Default is RUNTIME. @Target lists the allowed code elements via AnnotationTarget values such as CLASS, FUNCTION, PROPERTY, FIELD, VALUE_PARAMETER, CONSTRUCTOR, EXPRESSION, TYPE. If you omit @Target, the annotation may be applied to most declarations. Putting an annotation on a disallowed element is a compile error. Note that EXPRESSION targets require SOURCE retention because expressions aren't kept in bytecode.

code

kotlin · 8 lines
kotlin
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Audited

@Audited
class Service {
    @Audited fun run() {}
}

go deeper

for a junior

Knows Retention = lifetime, Target = location, and can name a few AnnotationTarget values.

for a middle

Recalls that RUNTIME is the default and only RUNTIME is reflection-visible; knows wrong target is a compile error.

for a senior

Explains the SOURCE/BINARY/RUNTIME tradeoffs and why EXPRESSION needs SOURCE retention.

for a principal

Frames retention/target choices in terms of API design, tooling integration, and binary-compatibility impact.

## Meta-annotations A **meta-annotation** is an annotation you place on an `annotation class` declaration to configure how that annotation behaves. `@Retention` and `@Target` are the two most important ones. ## @Retention — how long the annotation lives `@Retention` takes one value from the `AnnotationRetention` enum: - **SOURCE** — kept only during compilation, then thrown away. Useful for compiler hints / lint / annotation-processor markers that don't need to exist at runtime (e.g. `@Suppress`). - **BINARY** — stored in the compiled `.class` file (bytecode) but **not** visible to reflection at runtime. - **RUNTIME** — stored in the class file **and** readable at runtime through reflection (`kotlin.reflect` or Java reflection). This is the **default** if you don't specify `@Retention`. Only **RUNTIME** annotations can be read back with reflection such as `kClass.annotations` or `findAnnotation<T>()`. ## @Target — where the annotation may appear `@Target` takes one or more `AnnotationTarget` enum values. Common ones: - `CLASS` (classes, interfaces, objects, annotation classes) - `FUNCTION`, `PROPERTY`, `FIELD`, `LOCAL_VARIABLE` - `VALUE_PARAMETER` (function/constructor parameters) - `CONSTRUCTOR`, `PROPERTY_GETTER`, `PROPERTY_SETTER` - `TYPE`, `TYPE_PARAMETER`, `EXPRESSION`, `FILE`, `ANNOTATION_CLASS` If you apply the annotation to an element not in the list, the compiler raises an error: *"This annotation is not applicable to target ..."*. If you omit `@Target` entirely, the annotation defaults to being usable on most declaration sites (but not expressions/types). ## Example ```kotlin @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class Audited @Audited // OK: class class Service { @Audited // OK: function fun run() {} } // @Audited val x = 1 // compile error: not applicable to PROPERTY ``` ## Key constraints - `EXPRESSION` and `TYPE`-style targets generally require **SOURCE** retention, because expressions and most type usages aren't preserved in bytecode. - Defaults: retention defaults to **RUNTIME**; target defaults to a broad set of declarations.

  • If you don't specify @Retention, what do you get?
    RUNTIME retention by default, so the annotation is readable via reflection.
  • What happens if you put an annotation on a target not listed in @Target?
    A compile error: the annotation is not applicable to that element.

Retention is the shelf-life of a label; Target is the list of jars the label is allowed to be stuck on.

saying these in an interview costs you the question

  • Saying the default retention is SOURCE (it's RUNTIME)
  • Claiming @Target controls runtime visibility (that's @Retention)
  • Thinking SOURCE annotations are readable by reflection
  • Confusing meta-annotations with use-site targets like @get:/@field:

context