Both ways of writing the annotations apply @Inject and @CustomInfo onto the line lateinit var fieldA: Any.
However, there are multiple Java elements that are generated by this single Kotlin declaration - a backing field, a getter and setter - as well as the Kotlin property itself. The second way:
@field:[
Inject
CustomInfo
]
lateinit var fieldB: Any
explicitly states that you are applying these annotations to the underlying backing field.
The first way does not do that:
@Inject
@CustomInfo
lateinit var fieldA: Any
Instead, Kotlin uses its own documented rules (explained below) to decide which thing to apply your annotations on.
For each annotation, Kotlin finds all the targets available in the current context that the annotation can be applied on.
- If there is a parameter, it applies the annotation to the parameter.
- Otherwise, if there is a property, it applies the annotation to the property.
- Otherwise, if there is a field, it applies the annotation to the field.
Now looking at your two annotations, Inject is a Java annotation that can only be applied to fields, so for Inject, it doesn't which way you write it.
On the other hand, CustomInfo lacks a Target annotation, and so can be applied to both a property and a field (among other things). Kotlin would choose to apply it to the property if you do it this way:
@Inject
@CustomInfo
lateinit var fieldA: Any
Java code would not be able to find this annotation on the field! Looking at the decompiled code, it appears that the Kotlin compiler generates an additional, deprecated, synthetic method with @CustomInfo on it.
Side note: the [] doesn't actually create an "array". It's just some delimiters so that the parser (and the person reading the code) knows more easily which annotations are associated with @field: and which are not.
See also: Annotation Use-site Targets