In this section, WE continue with some of the more advanced stuff from Kotlin: notes from Kotlin.

Learning goals

  • A tool for architecture development;
  • Make the logic more concise, make the code more clear and easy to understand;
  • Can help you research and understand other frameworks;
  • The need to build your own wheels and use notes to solve problems;

For example, with annotations we can well implement pre-call permission detection, login interception, AOP and other functions

We’re probably all familiar with annotations, but how does Kotlin’s annotations look like, and how do they differ from the familiar Java annotations?

directory

  • What about Kotlin’s notes?
  • How do I declare Kotlin annotations?
  • How do I use Kotlin annotations?
  • Meta-annotations in Kotlin
  • Usage scenarios for annotations
  • Example: Custom annotations implement request method checking during API calls

What about Kotlin’s notes?

Annotations are designed to provide metadata to code, and annotations do not directly affect code execution. In Kotlin, the core concept of annotations is the same as In Java and is 100% compatible with Java annotations. An annotation allows you to associate additional metadata with a declaration, which can then be accessed in some way (such as runtime reflection and some source code tools).

An annotation is essentially a code tag that acts on code. It allows you to annotate specific annotation code with additional information. However, this information can be retained at different times, such as source time, compile time, and run time. Then, at various times, the tag information can be retrieved in some way to process the actual code logic, often in what we call reflection.

How do I declare Kotlin annotations?

Annotations are declared slightly differently in Kotlin than in Java, where they are declared primarily through the @Interface keyword, whereas in Kotlin they are declared only through the Annotation Class.

Declaration of Java annotations

Annotations in Java are defined by the @interface keyword, which is similar to an interface declaration, but with the @ prefix added
@interface ApiDoc {
     String value(a); 
}
Copy the code

Kotlin annotated declaration

// Just like a normal declaration, but with the annotation modifier in front of the class
annotation class ApiDoc(val value: String)
Copy the code

How do I use Kotlin annotations?

Using annotations in Kotlin is the same as in Java:

@ApiDoc("Modifiers")
class Box {
    @ApiDoc("Modify field")
    val size = 6

    @ApiDoc("Modification method")
    fun test(a){}}Copy the code

Meta-annotations in Kotlin

Just like in Java, in Kotlin a Kotlin annotation class can itself be annotated, and you can add annotations to the annotation class, which we call meta-annotations.

The meta-annotation classes in Kotlin are defined in the Kotlin. annotation package and include:

  • @target: Defines which Target objects the annotation can be applied to
  • @Retention: Retention period of notes
  • Repeatable: Tagged annotations can be applied multiple times to the same statement or type
  • @MustbeDocumented: Decorated annotations will be extracted by the documentation tool into the API document

When Inherited Inherited Inherited Inherited Inherited Inherited Inherited Inherited Inherited Inherited Inherited Inherited Inherited

@Target

@target is, as the name implies, the Target object, that is, we define annotations that can be applied to those Target objects, and can specify multiple Target objects at once.

The prototype of the @ Target

@Target(AnnotationTarget.ANNOTATION_CLASS)// You can label the tag by itself
@MustBeDocumented
public annotation class Target(vararg val allowedTargets: AnnotationTarget)
Copy the code

As you can see from the @target prototype, it takes a variable number of vararg arguments, so multiple Target objects can be specified at the same time, and the parameter type is limited to AnnotationTarget.

You can specify one or more Target objects in the @target annotation, so what Target objects are there? AnnotationTarget enumeration class AnnotationTarget enumeration class

AnnotationTarget

public enum class AnnotationTarget {
    CLASS, // Indicates that the object has classes, interfaces, object expressions, and annotation classes
    ANNOTATION_CLASS,// indicates that the object has only annotation classes
    TYPE_PARAMETER,// Indicates that the object is a generic type parameter (not yet supported)
    PROPERTY,// indicates that the object is an attribute
    FIELD,// Indicates that objects are fields, including fields behind attributes
    LOCAL_VARIABLE,// indicates that the object is a local variable
    VALUE_PARAMETER,// indicates that the object is an argument to a function or constructor
    CONSTRUCTOR,// indicates that the object is a constructor, primary constructor or secondary constructor
    FUNCTION,// indicates that the object is a function, excluding constructors
    PROPERTY_GETTER,// Indicates that the object is a getter for the property
    PROPERTY_SETTER,// indicates that the object is a setter function for the property
    TYPE,// Indicates that the object is a type, such as class, interface, enumeration
    EXPRESSION,// indicates that the object is an expression
    FILE,// Indicates that the object is a File
    @SinceKotlin("1.1")
    TYPEALIAS// Indicates that the object is a type alias
}
Copy the code

Once the annotation is qualified to @target, it can only be applied to the qualified Target. To verify this statement, we qualify the Target for ApiDoc:

@Target(AnnotationTarget.CLASS)
annotation class ApiDoc(val value: String)

@ApiDoc("Modifiers")
class Box {
    @ApiDoc("Modify field")
    val size = 6

    @ApiDoc("Modification method")
    fun test(a){}}Copy the code

This way, the ApiDoc annotation can only be applied to classes. If it is applied to methods or fields, an exception will be thrown:

This annotation is not applicable to target 'member property with backing field'
@Retention
Copy the code

@Retention

We can think of it as a retention period. Like Java, Kotlin has three periods:

  • SOURCE Age (SOURCE)
  • Compile time (BINARY)
  • RUNTIME.

@ Retention prototype

@ Target (AnnotationTarget ANNOTATION_CLASS) / / the Target object is annotation class public annotation class Retention (val value: AnnotationRetention = AnnotationRetention.RUNTIME)Copy the code

Retention receives an argument of type AnnotationRetention, which has a default value that is retained at run time.

AnnotationRetention

@RetentionMeta-annotation values are mainly derived from the AnnotationRetention enumeration classpublic enum class AnnotationRetention {
    SOURCE,// SOURCE: Annotations are not stored in the output class bytecode
    BINARY,// BINARY: Annotations are stored in the class bytecode, but not visible to reflection
    RUNTIME// RUNTIME: Annotations are stored in class bytecode and are also visible to reflection. The default is RUNTIME
}
Copy the code

Usage scenarios for annotations

  • Provide information to the compiler: The compiler can use annotations to handle things like warnings, errors, etc
  • Compile-time processing: Generating code using annotation information is common in Kotlin. Some built-in annotations generate additional code at compile time with the help of annotations for interoperability with Java apis
  • Runtime processing: Some annotations can be used to process some program logic while the program is running, using reflection to retrieve annotation information

Example: Custom annotations implement request method checking during API calls

public enum class Method {
    GET,
    POST
}

@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.RUNTIME)
annotation class HttpMethod(val method: Method)

interface Api {
    val name: String
    val version: String
        get() = "1.0"
}

@HttpMethod(Method.GET)
class ApiGetArticles : Api {
    override val name: String
        get() = "/api.articles"
}

fun fire(api: Api) {
    val annotations = api.javaClass.annotations
    val method = annotations.find { it is HttpMethod } as? HttpMethod
    println("It is noted by the annotations that the interface needs to pass:${method? .method}Mode request")}Copy the code