You must learn [Java annotation] to assist the code

Posted by GarroteYou on Sun, 28 Nov 2021 10:41:14 +0100

What is annotation πŸ‘»

Annotation is a special "Annotation" placed in front of classes, methods, fields and parameters of Java source code.

Some meta information attached to the code is used for parsing and using some tools during compilation and running, and plays the function of description and configuration.

Annotations do not and cannot affect the actual logic of the code, but only play an auxiliary role.

Annotations will be ignored by the compiler directly, and annotations can be packaged into class files by the compiler. Therefore, annotations are "metadata" used as annotations

What's the use of annotations? πŸ’€

From the perspective of the JVM, the annotation itself has no impact on the code logic, and how to use the annotation is entirely determined by the tool

1. Generate documents. This is the most common and the earliest annotation provided by java. Commonly used are @ param @return, etc
2. Track code dependencies and implement alternative configuration file functions.
3. Check the format at compile time. For example, @ override is placed in front of the method. If your method does not override the superclass method, it can be checked at compile time.

What is the principle of annotation? πŸ‘»

Annotation is essentially a special interface that inherits annotation, and its specific implementation class is a dynamic proxy class generated by Java runtime.

When the annotation is obtained through reflection, the dynamic proxy object $Proxy1 generated by the Java runtime is returned.

Calling the method of the custom annotation through the proxy object will eventually call the invoke() method of the AnnotationInvocationHandler.

This method will retrieve the corresponding value from the Map memberValues.

What are the types of annotations? 😺

**1, Annotation used by the compiler -- RetentionPolicy.SOURCE**

  • Will not be compiled into the. class file

  • @Override: let the compiler check whether the method implements the override correctly;

  • @SuppressWarnings: tells the compiler to ignore the warnings generated by the code here.

2, The tool handles the annotations used by the. Class file -- RetentionPolicy.CLASS

  • It will be compiled into the. class file, but it will not exist in memory after loading

3, Annotation that can be read during program running -- RetentionPolicy.RUNTIME

  • Always exists in the JVM after loading

Define annotation 😺

How to define annotations

The Java language uses @ interface syntax to define annotations

public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

/*
Can use default Set a default value (highly recommended). The most commonly used parameter should be named value

When defining an annotation, you can also define configuration parameters. Configuration parameters can include:

Because the configuration parameters must be constant, the above limitations ensure that the annotation has determined the value of each parameter at the time of definition.

Annotation configuration parameters can have default values. If a configuration parameter is missing, the default value will be used.

public class Hello {
    @Check(min=0, max=100, value=55)
    public int n;

    @Check(value=99)
    public int p;

    @Check(99) // @Check(value=99)
    public int x;

    @Check
    public int y;
}

Summary:

  • Define annotations with @ interface
  • Add parameters and default values.
    • Parameter members can only be decorated with public or default access rights
    • Only basic types can be used for parameter types
      • All basic types;
      • StringοΌ›
      • Enumeration type;
      • Arrays of basic types, strings, classes, and enumerations
  • Configuring annotations with meta annotations
    • @ Target and @ Retention must be set, and @ Retention is generally set to RUNTIME
    • In general, it is not necessary to write @ Inherited and @ Repeatable

Meta annotation

Annotations that modify annotations: meta annotation

@Target

Use @ Target to define where annotations can be applied to the source code:

  • Class or interface: ElementType.TYPE
  • Member variables, objects, properties (including enum instances): ElementType.FIELD
  • Method: ElementType.METHOD
  • Construction method: ElementType.CONSTRUCTOR
  • Method parameter: ElementType.PARAMETER
  • Local variable: ElementType.LOCAL_VARIABLE
  • Package: ElementType.PACKAGE
//Define that the annotation @ Report can be used on the method. We must add a @ Target(ElementType.METHOD)

@Target(ElementType.METHOD)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

//Define the annotation @ Report, which can be used on methods or fields. You can change the @ Target annotation parameter into an array {ElementType.METHOD, ElementType.FIELD}
@Target({
    ElementType.METHOD,
    ElementType.FIELD
})
public @interface Report {
	.....
}

@The value defined by Target is an ElementType [] array. When there is only one element, the writing of the array can be omitted

@Retention

The meta Annotation @ Retention defines the lifecycle of an Annotation:

  • Compile time only: RetentionPolicy.SOURCE, which will not be compiled into the. class file
  • Only the class file: RetentionPolicy.CLASS. It will not exist in memory after loading
  • Runtime: RetentionPolicy.RUNTIME, which will always exist in memory after loading
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

be careful:

  • If @ Retention does not exist, the Annotation defaults to CLASS

  • Usually, our customized Annotation is RUNTIME, so be sure to add the meta Annotation @ Retention(RetentionPolicy.RUNTIME) to read the Annotation during operation

@Repeatable

@Repeatable meta Annotation can define whether the Annotation is repeatable

@Repeatable(Reports.class) //Reports class. Annotations are repeatable
@Target(ElementType.TYPE)	//Class or interface
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

@Target(ElementType.TYPE)
public @interface Reports {
    Report[] value();
}

After being decorated with @ Repeatable, multiple @ Report annotations can be added at a type declaration

@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello {
}

@Inherited

@Inherited defines whether the subclass can inherit the annotation defined by the parent class, @ inherited is only valid for the annotation of @ Target(ElementType.TYPE) type, and only for the inheritance of class, but not for the inheritance of interface

@Inherited
@Target(ElementType.TYPE)
public @interface Report {
    int type() default 0;
    String level() default "info";
    String value() default "";
}

When using @ Report, if a class uses @ Report:

@Report(type=1)
public class Person {
}

Its subclass also defines the annotation by default:

public class Student extends Person {
}

@Documented

A simple Annotations tag indicates whether to add annotation information to the java document

How to handle annotations πŸ‘»

The Java annotation itself has no effect on the code logic. According to the configuration of @ Retention:

  • The annotation of SOURCE type is discarded at compile time; it is mainly used by the compiler, only used and not written
  • Class type annotations are only saved in the class file and will not be loaded into the JVM; they are used by the underlying tool library and involve class loading, which is rarely used
  • The RUNTIME annotation is loaded into the JVM and can be read by the program at run time. It is not only used, but also often written

After the annotation is defined, it is also a class. All annotations are inherited from java.lang.annotation.Annotation

Reflection API is required to read annotations.

  • Judge whether an annotation exists in Class, Field, Method or Constructor:

    • Class.isAnnotationPresent(Class)
    • Field.isAnnotationPresent(Class)
    • Method.isAnnotationPresent(Class)
    • Constructor.isAnnotationPresent(Class)
  • To read annotations using the reflection API:

    • The first method: first judge whether the Annotation exists. If so, read it directly

      The second method: read the Annotation directly. If the Annotation does not exist, it will return null

    • Class.getAnnotation(Class)

    • Field.getAnnotation(Class)

    • Method.getAnnotation(Class)

    • Constructor.getAnnotation(Class)

  • Read Annotation of method parameters

All annotations that get method parameters at once must be represented by a two-dimensional array

public void hello(@NotNull @Range(max=5) String name, @NotNull String prefix) {
}


// Get Method instance:
Method m = ...
// Get Annotation for all parameters:
Annotation[][] annos = m.getParameterAnnotations();
// All annotations for the first parameter (index 0):
Annotation[] annosOfName = annos[0];
for (Annotation anno : annosOfName) {
    if (anno instanceof Range) { // @Range annotation
        Range r = (Range) anno;
    }
    if (anno instanceof NotNull) { // @NotNull annotation
        NotNull n = (NotNull) anno;
    }
}

How to use annotations πŸ’€

How annotations are used is entirely up to the program itself

JUnit is a testing framework that automatically runs all methods marked @ Test

example:

/*
This is a @ Range annotation,
It defines the rule of a String field: the field length meets the parameter definition of @ Range
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {
    int min() default 0;
    int max() default 255;
}

//Use this annotation in a JavaBean
//Annotations are defined and have no effect on program logic. We must write our own code to use annotations
public class Person {
    @Range(min=1, max=20)
    public String name;

    @Range(max=10)
    public String city;
}


//The checking logic is completely written by ourselves, and the JVM will not automatically add any additional logic to the annotation
void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
    // Traverse all fields:
    for (Field field : person.getClass().getFields()) {
        // Get the @ Range:
        Range range = field.getAnnotation(Range.class);
        // If @ Range exists:
        if (range != null) {
            // Get the value of Field:
            Object value = field.get(person);
            // If the value is String:
            if (value instanceof String) {
                String s = (String) value;
                // Judge whether the value meets the min/max of @ Range:
                if (s.length() < range.min() || s.length() > range.max()) {
                    throw new IllegalArgumentException("Invalid field: " + field.getName());
                }
            }
        }
    }
}

reference material

[1] http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html
[2] http://www.cnblogs.com/whoislcj/p/5671622.html
[3] http://blog.csdn.net/lylwo317/article/details/52163304
[4] Implementation principle of Annotation and example of user-defined Annotation

Topics: Java Annotation