Annotations are means of attaching metadata to code. To declare an annotation, put the
annotation modifier in front of a class:
Additional attributes of the annotation can be specified by annotating the annotation class with meta-annotations:
@Targetspecifies the possible kinds of elements which can be annotated with the annotation (such as classes, functions, properties, and expressions);
@Retentionspecifies whether the annotation is stored in the compiled class files and whether it's visible through reflection at runtime (by default, both are true);
@Repeatableallows using the same annotation on a single element multiple times;
@MustBeDocumentedspecifies that the annotation is part of the public API and should be included in the class or method signature shown in the generated API documentation.
If you need to annotate the primary constructor of a class, you need to add the
constructor keyword to the constructor declaration, and add the annotations before it:
You can also annotate property accessors:
Annotations can have constructors that take parameters.
Allowed parameter types are:
Types that correspond to Java primitive types (Int, Long etc.)
Arrays of the types listed above
Annotation parameters cannot have nullable types, because the JVM does not support storing
null as a value of an annotation attribute.
If an annotation is used as a parameter of another annotation, its name is not prefixed with the
If you need to specify a class as an argument of an annotation, use a Kotlin class (KClass). The Kotlin compiler will automatically convert it to a Java class, so that the Java code can access the annotations and arguments normally.
In Java, an annotation type is a form of an interface, so you can implement it and use an instance. As an alternative to this mechanism, Kotlin lets you call a constructor of an annotation class in arbitrary code and similarly use the resulting instance.
Learn more about instantiation of annotation classes in this KEEP.
Annotations can also be used on lambdas. They will be applied to the
invoke() method into which the body of the lambda is generated. This is useful for frameworks like Quasar, which uses annotations for concurrency control.
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:
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:
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:
The full list of supported use-site targets is:
property(annotations with this target are not visible to Java)
receiver(receiver parameter of an extension function or property)
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:
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:
Java annotations are 100% compatible with Kotlin:
Since the order of parameters for an annotation written in Java is not defined, you can't use a regular function call syntax for passing the arguments. Instead, you need to use the named argument syntax:
Just like in Java, a special case is the
value parameter; its value can be specified without an explicit name:
Arrays as annotation parameters
value argument in Java has an array type, it becomes a
vararg parameter in Kotlin:
For other arguments that have an array type, you need to use the array literal syntax or
Accessing properties of an annotation instance
Values of an annotation instance are exposed as properties to Kotlin code:
Ability to not generate JVM 1.8+ annotation targets
If a Kotlin annotation has
TYPE among its Kotlin targets, the annotation maps to
java.lang.annotation.ElementType.TYPE_USE in its list of Java annotation targets. This is just like how the
TYPE_PARAMETER Kotlin target maps to the
java.lang.annotation.ElementType.TYPE_PARAMETER Java target. This is an issue for Android clients with API levels less than 26, which don't have these targets in the API.
To avoid generating the
TYPE_PARAMETER annotation targets, use the new compiler argument
Just like in Java, Kotlin has repeatable annotations, which can be applied to a single code element multiple times. To make your annotation repeatable, mark its declaration with the
@kotlin.annotation.Repeatable meta-annotation. This will make it repeatable both in Kotlin and Java. Java repeatable annotations are also supported from the Kotlin side.
The main difference with the scheme used in Java is the absence of a containing annotation, which the Kotlin compiler generates automatically with a predefined name. For an annotation in the example below, it will generate the containing annotation
You can set a custom name for a containing annotation by applying the
@kotlin.jvm.JvmRepeatable meta-annotation and passing an explicitly declared containing annotation class as an argument:
To extract Kotlin or Java repeatable annotations via reflection, use the
Learn more about Kotlin repeatable annotations in this KEEP.