SoFunction
Updated on 2025-03-06

Detailed explanations and examples of Kotlin's annotation class

Detailed explanations and examples of Kotlin's annotation class

Annotation statement

Annotations are methods of appending metadata to code. To declare annotation, place the annotation modifier in front of the class:

annotation class Fancy

Additional attributes of annotations can be specified by annotating the annotation class with meta annotations:

  1. @Target Specifies possible types (classes, functions, attributes, expressions, etc.) of elements that can be annotated with this annotation;
  2. @Retention Specifies whether the annotation is stored in the compiled class file and whether it can be visible through reflection at runtime (the default is true);
  3. @Repeatable allows the same annotation to be used multiple times on a single element;
  4. @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.VALUE_PARAMETER, )
@Retention()
@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 a class, you need to add the constructor keyword in the constructor declaration and add the annotation to its front:

class Foo @Inject constructor(dependency: MyDependency) {
  // ……
}

You can also label the property accessor:

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:

  1. Types corresponding to Java native types (Int, Long, etc.);
  2. string;
  3. class (Foo::class);
  4. enumerate;
  5. Other notes;
  6. Array of type columned above.

Annotation parameters cannot have null types because the JVM does not support storing null as the value of the annotation property.

If the 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 to a Java class so that the Java code can see the annotation and parameters normally.

import 

annotation class Ann(val arg1: KClass<*>, val arg2: KClass<out Any?>)

@Ann(String::class, Int::class) class MyClass

Lambda expressions

Annotations can also be used in lambda expressions. They are applied to the invoke() method that generates the lambda expression body. This is useful for frameworks like Quasar, which uses annotations for concurrent control.

annotation class Suspendable

val f = @Suspendable { (10) }

Annotation usage target

When annotating attributes or main constructor parameters, there will be multiple Java elements generated from the corresponding Kotlin element, so there are multiple possible locations for this annotation 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,  // Tag Java fields       @get:Ann val bar,   // Tag Java getter       @param:Ann val quux)  // Annotate Java constructor parameters

The same syntax can be used to label the entire file. To do this, place the annotation with the target file at the top level of the file, before the package directive, or before all imports (if the file is in the default package):

@file:JvmName("Foo")

package 

If you have multiple annotations for the same target, you can avoid duplication of the target by adding square brackets after the target and putting all annotations in square brackets:

class Example {
   @set:[Inject VisibleForTesting]
   var collaborator: Collaborator
}

The complete list of supported usage targets is:

  1. file
  2. property (annotations with this target are not visible to Java)
  3. field
  4. get (property getter)
  5. set (property setter)
  6. receiver (receiver parameter of extended function or attribute)
  7. param (constructor parameter)
  8. setparam (property setter parameter)
  9. delegate (the field that stores its delegate instance for the delegate attribute)

To annotate the receiver parameters of the extension function, use the following syntax:

fun @receiver:Fancy () { }

If the target is not specified, the target is selected based on the @Target annotation of the annotation being used. If there are multiple applicable targets, use the first applicable target in the following list:

  • param
  • property
  • field

Java Annotations

Java annotations are 100% compatible with Kotlin:

import 
import .*
import 
import .*

class Tests {
  // Apply the @Rule annotation to the property getter  @get:Rule val tempFolder = TemporaryFolder()

  @Test fun simple() {
    val f = ()
    assertEquals(42, getTheAnswer())
  }
}

Because Java-written annotations do not define the parameter order, the parameters cannot be passed using regular 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

Just like in Java, a special case is the value parameter; its value does not need to be specified explicitly.

// Java
public @interface AnnWithValue {
  String value();
}
// Kotlin
@AnnWithValue("abc") class C

If the value parameter in Java has an array type, it becomes a vararg parameter in Kotlin:

// Java
public @interface AnnWithArrayValue {
  String[] value();
}
// Kotlin
@AnnWithArrayValue("abc", "foo", "bar") class C

For other parameters with array type, you need to explicitly use arrayOf:

// Java
public @interface AnnWithArrayMethod {
  String[] names();
}
// Kotlin
@AnnWithArrayMethod(names = arrayOf("abc", "foo", "bar")) class C

The value of the annotated instance is exposed to the Kotlin code as an attribute.

// Java
public @interface Ann {
  int value();
}
// Kotlin
fun foo(ann: Ann) {
  val i = 
}

Thank you for reading, I hope it can help you. Thank you for your support for this site!