skip to content

What is a use-site target on a Kotlin annotation (e.g. @get:, @field:, @param:), and why is it needed when annotating a property?

level: juniorimportance: must knowfreq 70%

answer

  1. One property = field + getter + setter + ctor param
  2. Prefix before the colon: @get:/@field:/@param:
  3. Wrong target = annotation silently ignored
  4. Targets: get/set/field/param/property/receiver/delegate

basics

~20 s

One Kotlin property can become several Java pieces: a field, a getter, a setter, a constructor parameter. A use-site target like @get: or @field: tells the compiler which of those pieces the annotation should land on.

solid answer

~40 s

A property declaration in Kotlin generates multiple JVM elements: a backing field, a getter, optionally a setter, and (for primary-constructor properties) a constructor parameter. An annotation written on the property is ambiguous about which element it targets, so Kotlin lets you disambiguate with a use-site target prefix: `@get:`, `@set:`, `@field:`, `@param:`, `@property:`, `@receiver:`, and `@delegate:`. For example `@field:JsonProperty("id")` puts the annotation on the Java field, while `@get:JsonProperty("id")` puts it on the getter. This matters because libraries that use reflection (Jackson, JPA, validation) inspect a specific element; targeting the wrong one means the annotation is silently ignored. If you omit the target, Kotlin applies a default resolution order based on the annotation's `@Target`.

code

kotlin · 5 lines
kotlin
class Account(
    @field:Id val id: Long,                 // annotation on the field
    @get:JsonProperty("user_name") val name: String, // on the getter
    @param:Positive val balance: Long,      // on the ctor parameter
)

go deeper

for a junior

Knows a property maps to multiple JVM elements and that @get:/@field:/@param: choose one.

for a middle

Can predict which library reads which element and fix a silently-ignored annotation.

for a senior

Explains the default resolution order and the full target set including @property:/@delegate:.

for a principal

Frames it as a Kotlin-to-JVM impedance issue and sets team conventions for interop annotations.

## The problem use-site targets solve In Kotlin, a single line like `val id: Long` is more than a field. When compiled to JVM bytecode, a property can produce **several distinct elements**: - a **backing field** (the actual storage slot) - a **getter** method - a **setter** method (only for `var`) - a **constructor parameter** (only when the property is declared in the primary constructor) If you write `@SomeAnnotation val id: Long`, the compiler must decide which of these the annotation belongs to. A **use-site target** is a prefix before the colon that removes the ambiguity. ## The available targets ```kotlin class User( @param:NotBlank val name: String, // the constructor parameter @field:Id val id: Long, // the backing field @get:JsonProperty("email") val email: String, // the getter ) ``` The full set: - `@get:` — the property getter - `@set:` — the property setter (only valid on `var`) - `@field:` — the backing field - `@param:` — the primary-constructor parameter - `@property:` — the Kotlin property itself (a Kotlin-only target, stored in metadata) - `@receiver:` — the receiver parameter of an extension function/property - `@delegate:` — the field that stores a delegate instance (`by`) ## Why it matters in practice Many Java libraries read annotations **reflectively** off a *specific* element. Jackson and JPA often look at fields **or** getters; Bean Validation may look at the field, the getter, or the constructor parameter depending on configuration. If your annotation lands on the wrong element, it is simply ignored — no error, just silently wrong behavior. That makes the wrong-target bug hard to spot. ## Default behavior If you don't specify a target, Kotlin doesn't pick randomly — it follows a fixed **default resolution order** based on which targets the annotation declares in its `@Target`. (Covered in depth in a separate question.)

  • What happens if you put an annotation on a property without any use-site target?
    Kotlin applies the default resolution order: it picks the first applicable target from the list param, property, field (skipping ones not allowed by the annotation's @Target).
  • Why might a Jackson @JsonProperty annotation appear to do nothing?
    It probably landed on the wrong element. If Jackson reads getters but the annotation defaulted onto the field (or vice versa), it is ignored. Adding @get: or @field: fixes it.

Like addressing a letter to one specific person in a shared household — without the name, the mail goes to whoever the default rule says.

saying these in an interview costs you the question

  • Thinking a Kotlin property is just a field
  • Claiming the target prefix is optional cosmetic syntax with no effect
  • Saying a wrong target causes a compile error (it usually doesn't)
  • Confusing use-site targets with the annotation's own @Target meta-annotation

context