Annotation statement
Annotations are a way to attach metadata to code. To declare annotations, place the annotation modifier in front of the class
annotation class Fancy
Additional attributes of annotations can be specified by annotating annotation classes with meta annotations
- @ Target specifies the possible types of elements that can be marked with this annotation (class, function, attribute, expression, etc.);
- @ Retention specifies whether the annotation is stored in the compiled class file and whether it can be reflected at run time (true by default);
- @ Repeatable allows the same annotation to be used multiple times on a single element;
- @ MustBeDocumented specifies that the annotation is part of the public API and should be included in the signature of the class or method displayed in the generated API document.
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION,
AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.EXPRESSION) @Retention(AnnotationRetention.SOURCE) @MustBeDocumented annotation class Fancy
usage
@Fancy class Foo { @Fancy fun baz(@Fancy foo: Int): Int { return (@Fancy 1) } }
If you need to annotate the main constructor of the class, you need to add the constructor keyword in the constructor declaration and add the annotation in front of it
class Foo @Inject constructor(dependency: MyDependency) { ...... }
You can also label attribute accessors
class Foo { var x: MyDependency? = null @Inject set }
Constructor
Annotations can have constructors that accept parameters
annotation class Special(val why: String) @Special("example") class Foo {}
The allowed parameter types are
- types corresponding to Java Native types (Int, Long, etc.) character string;
- class (Foo::class);
- enumeration;
- other notes;
- an array of types listed above.
Annotation parameters cannot have nullable types because the JVM does not support storing null as the value of annotation properties.
If an annotation is used as a parameter to another annotation, its name is not prefixed with the @ character
annotation class ReplaceWith(val expression: String) annotation class Deprecated(
val message: String, val replaceWith: ReplaceWith = ReplaceWith("")
) @Deprecated("This function is deprecated, use === instead", ReplaceWith("this === other"))
If you need to specify a class as an annotation parameter, use the Kotlin class (KClass). The Kotlin compiler will automatically convert it into a Java class so that Java code can normally access the annotation and parameters
import kotlin.reflect.KClass annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any>) @Ann(String::class, Int::class) class MyClass
Lambda expression
Annotations can also be used for lambda expressions. They are applied to the invoke() method that generates the body of the lambda expression. This is useful for frameworks like Quasar, which uses annotations for concurrency control
annotation class Suspendable val f = @Suspendable { Fiber.sleep(10) }
Target where annotation is used
When labeling attributes or main constructor parameters, there will be multiple Java elements generated from the corresponding Kotlin element, so the annotation has multiple possible positions in the generated Java bytecode. If you want to specify exactly how the annotation should be generated, use the following syntax
class Example(
@field:Ann val foo,// Annotate Java fields
@get:Ann val bar,// Annotation Java getter
@param:Ann val quux// Annotate Java constructor parameters
)
You can use the same syntax to label the entire file. To do this, place the annotation with the target file at the top of the 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 comments on the same goal, you can avoid duplication of goals by adding square brackets after the goal and putting all comments in square brackets
class Example { @set:[Inject VisibleForTesting] var collaborator: Collaborator }
The complete list of supported usage targets is
— file;
- property (annotations with this goal are not applicable to Java);
— field ;
- get (attribute getter);
- set (property setter);
- receiver (receiver parameter of extension function or attribute);
- param (constructor parameter);
- SetParam (property setter parameter);
- delegate (the field that stores its delegate instance for the delegate attribute)
To label the receiver parameter of an extension function, use the following syntax
fun @receiver:Fancy String.myExtension() { ... }
If you do not specify a Target at use, select the Target according to the @ Target annotation of the annotation you are using. If there are multiple applicable targets, use the first applicable Target in the following list
— param ;
— property ;
— field
Java annotation
Java annotations are 100% compatible with kotlin
import org.junit.Test import org.junit.Assert.* import org.junit.Rule import org.junit.rules.* class Tests { // Apply @ Rule annotation to attribute getter @get:Rule val tempFolder = TemporaryFolder() @Test fun simple() { val f = tempFolder.newFile() assertEquals(42, getTheAnswer()) } }
Because annotations written in Java do not define the order of parameters, you cannot pass parameters using normal function call syntax. Instead, you need to use named parameter syntax
// Java public @interface Ann { int intValue(); String stringValue(); }
// Kotlin @Ann(intValue = 1, stringValue = "abc") class C
As in Java, a special case is the value parameter; Its value does not need to be specified by an explicit name
// Java public @interface AnnWithValue { String value(); }
// Kotlin @AnnWithValue("abc") class C
Array as annotation parameter
If the value parameter in Java has an array type, it will become a vararg parameter in Kotlin
// Java public @interface AnnWithArrayValue { String[] value(); }
// Kotlin @AnnWithArrayValue("abc", "foo", "bar") class C
For other parameters with array types, you need to explicitly use array literal syntax (since Kotlin 1.2) or arrayOf(...)
// Java public @interface AnnWithArrayMethod { String[] names(); }
/ Kotlin 1.2+: @AnnWithArrayMethod(names = ["abc", "foo", "bar"]) class C // Old version Kotlin: @AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar")) class D
Accessing the properties of an annotation instance
The value of the annotation instance is exposed to the Kotlin code as an attribute
// Java public @interface Ann { int value(); }
// Kotlin fun foo(ann: Ann) { val i = ann.value }