What Happens If You Don’t Specify a Use-Site Target in Kotlin?

Table of Contents

In Kotlin, annotations can target multiple elements of a declaration — such as a field, getter, or constructor parameter. When you apply an annotation without explicitly specifying a use-site target (e.g., @MyAnnotation instead of @field:MyAnnotation), Kotlin tries to infer the most appropriate placement.

This default behavior often works well — but in some cases, especially when interoperating with Java frameworks, it can produce unexpected results. Let’s dive into how it works, and what’s changing with Kotlin 2.2.0.

Default Target Inference in Kotlin (Before 2.2.0)

If the annotation supports multiple targets (defined via its @Target declaration), Kotlin infers where to apply the annotation based on context. This is especially relevant for primary constructor properties.

Kotlin
annotation class MyAnnotation
class User(
    @MyAnnotation val name: String
)

In this case, Kotlin might apply @MyAnnotation to the constructor parameter, property, or field—depending on what @MyAnnotation allows.

Approximate Priority Order:

When multiple targets are applicable, Kotlin historically followed a rough order of priority:

  1. param – Constructor parameter
  2. property – The Kotlin property itself
  3. field – The backing field generated in bytecode

But this is not a strict rule — the behavior varies by context and Kotlin version.

Interop with Java Frameworks: Why Target Matters

Kotlin properties can generate several elements in Java bytecode:

  • A backing field
  • A getter method (and setter for var)
  • A constructor parameter (for primary constructor properties)

Java frameworks (like Jackson, Spring, Hibernate) often look for annotations in specific places — typically on the field or getter. If Kotlin places the annotation somewhere else (e.g., the property), the framework might not recognize it.

Kotlin
class User(
    @JsonProperty("username") val name: String
)

If @JsonProperty is placed on the property instead of the field, Jackson may not detect it correctly. The fix is to use an explicit target:

Kotlin
class User(
    @field:JsonProperty("username") val name: String
)

Kotlin 2.2.0: Refined Defaulting with -Xannotation-default-target

Kotlin 2.2.0 introduces a new experimental compiler flag:

Kotlin
-Xannotation-default-target=param-property

When enabled, this flag enforces a consistent and more predictable defaulting strategy, especially suited for Java interop.

New Priority Order:

  1. param – If valid, apply to the constructor parameter
  2. property – If param isn’t valid, and property is
  3. field – If neither param nor property is valid, but field is
  4. Error — If none of these are allowed, compilation fails

This makes annotation behavior more intuitive, especially when integrating with Java-based tools and frameworks.

The @all: Meta-Target (Experimental)

Kotlin 2.2.0 also introduces the experimental @all: use-site target, which applies an annotation to all applicable parts of a property:

  • param (constructor parameter)
  • property (Kotlin-level property)
  • field (backing field)
  • get (getter)
  • set (setter, if var)

Example:

Kotlin
@all:MyAnnotation<br>var name: String = ""

This is equivalent to writing:

Kotlin
@param:MyAnnotation
@property:MyAnnotation
@field:MyAnnotation
@get:MyAnnotation
@set:MyAnnotation

Only the targets supported in the annotation’s @Target list will be applied.

Best Practices

Here’s how to work with Kotlin annotations effectively:

ScenarioRecommendation
Using annotations with Java frameworksUse explicit use-site targets (@field:, @get:)
Want consistent defaultingEnable -Xannotation-default-target=param-property
Want broad annotation coverageUse @all: (if supported by the annotation)
Unsure where an annotation is being appliedUse the Kotlin compiler flag -Xemit-jvm-type-annotations and inspect bytecode or decompiled Java

Conclusion

While Kotlin’s inferred annotation targets are convenient, they don’t always align with Java’s expectations. Starting with Kotlin 2.2.0, you get more control and predictability with:

  • Explicit use-site targets
  • A refined defaulting flag (-Xannotation-default-target)
  • The @all: meta-target for multi-component coverage

By understanding and controlling annotation placement, you’ll avoid hidden bugs and ensure smooth Kotlin–Java interop.

Skill Up: Software & AI Updates!

Receive our latest insights and updates directly to your inbox

Related Posts

error: Content is protected !!