How does @Target govern annotation placement, what happens if you omit it, and how does it interact with @Repeatable for a multi-target annotation?
answer
- @Target = whitelist of AnnotationTarget kinds, compiler-enforced
- Omit it -> broad default set, but NOT expression/file/type
- EXPRESSION target requires SOURCE retention
- @Target and @Repeatable are orthogonal
- Narrowest target set = best misuse feedback
basics
~10 s@Target lists the kinds of code an annotation may be put on. Omit it and the annotation is allowed on most targets. Using it on a disallowed target is a compile error.
solid answer
~40 s`@Target(vararg allowedTargets: AnnotationTarget)` whitelists the program elements an annotation may legally annotate — values like `CLASS`, `FUNCTION`, `PROPERTY`, `FIELD`, `VALUE_PARAMETER`, `TYPE`, `EXPRESSION`, `FILE`, `ANNOTATION_CLASS`. If you place the annotation on an element not in the list, the compiler rejects it. If you **omit** `@Target`, the annotation defaults to a broad set of common targets (it is *not* unrestricted to absolutely everything — e.g. `EXPRESSION`, `FILE`, and `TYPE` are not in the default set, so you must list those explicitly). `@Target` is independent of `@Repeatable`: a multi-target annotation can also be repeatable, and repetition is allowed on any element among its declared targets. Note `EXPRESSION`-targeted annotations require `SOURCE` retention, since expressions aren't represented in bytecode.
code
kotlin · 11 lines@Repeatable
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
annotation class Tag(val value: String)
@Tag("a") @Tag("b")
class Multi
@Tag("x")
fun process() {}
// @Tag("y") val n = 1 // error: PROPERTY not in @Targetgo deeper
Knows @Target lists allowed places and that wrong placement is a compile error.
Knows omitting @Target gives a broad default and can enumerate common AnnotationTarget values.
Knows the default excludes EXPRESSION/FILE/TYPE, that EXPRESSION needs SOURCE retention, and that @Target/@Repeatable compose orthogonally.
Advocates narrowest-target API design for compile-time safety and reasons about target choices for library ergonomics and interop.
## What @Target does `@Target` enumerates which `AnnotationTarget` kinds your annotation may be applied to. The compiler **enforces** it: applying the annotation to anything outside the list is a compile error. Common `AnnotationTarget` values: - `CLASS` (classes, interfaces, objects, annotation classes), `ANNOTATION_CLASS` - `FUNCTION`, `PROPERTY`, `FIELD`, `LOCAL_VARIABLE` - `VALUE_PARAMETER` (constructor/function params), `CONSTRUCTOR` - `PROPERTY_GETTER`, `PROPERTY_SETTER` - `TYPE` (type usages), `TYPE_PARAMETER`, `TYPEALIAS` - `EXPRESSION`, `FILE` ```kotlin @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) annotation class Audited @Audited class Service // ok @Audited fun handle() {} // ok // @Audited val x = 1 // compile error: PROPERTY not allowed ``` ## Omitting @Target If you don't specify `@Target`, the annotation is allowed on a **default broad set** of declaration targets — but this is **not literally every** target. Notably `EXPRESSION`, `FILE`, and `TYPE` are **excluded** from the default and must be listed explicitly if you need them: ```kotlin annotation class Marker // usable on classes, functions, properties, etc. // but NOT on an expression unless you add AnnotationTarget.EXPRESSION ``` ## Special cases - **`EXPRESSION` requires `SOURCE` retention.** Expressions have no bytecode representation, so an expression-target annotation cannot be `BINARY`/`RUNTIME`; the compiler enforces this pairing. - **`FILE`** targets a whole file and is used with a file-level use-site target (`@file:...`). ## Interaction with @Repeatable `@Target` and `@Repeatable` are **orthogonal** meta-annotations and compose freely: ```kotlin @Repeatable @Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) annotation class Tag(val value: String) @Tag("a") @Tag("b") class Multi // repeated on a CLASS target — allowed @Tag("x") @Tag("y") fun process() {} // repeated on a FUNCTION target — allowed ``` Repetition is permitted on any element listed in `@Target`; it doesn't add or remove allowed targets. To read all occurrences reflectively you still need `RUNTIME` retention plus `findAnnotations<T>()`. ## Design guidance Declare the **narrowest** target set that fits the intent. A tight `@Target` turns misuse into compile errors at the call site instead of silent no-ops, which is far better feedback for consumers of a library annotation.
- Why can't an EXPRESSION-targeted annotation be RUNTIME?Expressions are not represented in the compiled bytecode, so there is nowhere to store the annotation for the runtime to read. The compiler therefore requires SOURCE retention for AnnotationTarget.EXPRESSION.
- If you omit @Target, can you annotate a type usage like List<@Marker String>?No. TYPE is not in the default target set, so you must add AnnotationTarget.TYPE explicitly to annotate a type usage.
Like a power outlet shaped for specific plugs: anything that doesn't fit simply won't go in (compile error).
saying these in an interview costs you the question
- Claiming omitting @Target allows literally every target including EXPRESSION/FILE/TYPE
- Saying a disallowed target is a runtime error rather than compile error
- Thinking @Repeatable changes which targets are allowed
- Not knowing EXPRESSION requires SOURCE retention
- Defaulting to a maximally broad target set for library annotations