TL;DR: The field:
part is known as a “use-site target”, and makes it clear that the annotation is applied to the backing field of the Kotlin property. It is not strictly necessary in this case, though it can make the code more readable.
Explanation
To simplify, let’s say you have:
data class Repo(
@field:SerializedName("name")
var name: String
)
That code is declaring a data class along with its properties via the primary constructor. Kotlin properties are made up of the property itself, a getter, and—if mutable—a setter. What does all this mean for us? It means there’s a lot going on here for just one little property. In this context, the annotation on name
could1 apply to any one of the following:
- The constructor parameter.
- The Kotlin property itself.
- The getter.
- The setter.
- The setter’s parameter.
- The backing field of the property.
By using field:
, which is known as a “use-site target”, you make it clear the annotation is applied to the backing field of the property. No more ambiguity1.
However, I should note that not using field:
in this case would still result in the annotation being applied to the backing field. As described in the documentation below, if no use-site target is used, then Kotlin looks at the @Target
meta-annotation. From there, it applies the annotation to the first valid target from param
(constructor parameter), property
(Koltin property), and field
(backing field), in that order. The @SerializedName
2 annotation is not applicable to param
s. And due to it being a Java annotation, it can’t possibly be applicable to property
s. But the annotation is applicable to field
s, and so that’s where it would end up.
1. There’s not any true ambiguity, because the rules are clearly defined (see the documentation below). But that’s regarding the compiler. For a human, at first glance the code may be unclear, and that’s really what matters. The use-site target may not be strictly necessary, but it makes the code more readable (at least, in my opinion).
2. You’ve tagged this question with gson, and so that’s where I assume the annotation is from.
Documentation
Here’s the Kotlin documentation discussing this:
Annotation Use-site Targets
When you’re annotating a property or a primary constructor parameter, there are multiple Java elements which are generated from the corresponding Kotlin element, and therefore multiple possible locations for the annotation in the generated Java bytecode. To specify how exactly the annotation should be generated, use the following syntax:
class Example(@field:Ann val foo, // annotate Java field @get:Ann val bar, // annotate Java getter @param:Ann val quux) // annotate Java constructor parameter
The same syntax can be used to annotate the entire file. To do this, put an annotation with the target
file
at the top level of a file, before the package directive or before all imports if the file is in the default package:@file:JvmName("Foo") package org.jetbrains.demo
If you have multiple annotations with the same target, you can avoid repeating the target by adding brackets after the target and putting all the annotations inside the brackets:
class Example { @set:[Inject VisibleForTesting] var collaborator: Collaborator }
The full list of supported use-site targets is:
file
;property
(annotations with this target are not visible to Java);field
;get
(property getter);set
(property setter);receiver
(receiver parameter of an extension function or property);param
(constructor parameter);setparam
(property setter parameter);delegate
(the field storing the delegate instance for a delegated property).To annotate the receiver parameter of an extension function, use the following syntax:
fun @receiver:Fancy String.myExtension() { ... }
If you don’t specify a use-site target, the target is chosen according to the
@Target
annotation of the annotation being used. If there are multiple applicable targets, the first applicable target from the following list is used:
param
;property
;field
.