More language structures of kotlin - > annotation

Posted by whare on Thu, 27 Jan 2022 05:53:58 +0100

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
}