Annotation in Java and its implementation principle

Annotation in Java and its implementation principle

What is annotation?

For many first-time developers should have this question? Annotation is a new feature introduced in Java 5. Its Chinese name is annotation. It provides a secure annotation like mechanism to associate any information or metadata with program elements (classes, methods, member variables, etc.). Add more intuitive and clear descriptions to the elements (classes, methods, member variables) of the program. These descriptions are independent of the business logic of the program and are used by the specified tools or frameworks.

Like a modifier, annotation is applied to the declaration statements of packages, types, constructors, methods, member variables, parameters and local variables. Java annotation is some meta information attached to the code, which is used for parsing and using some tools during compilation and runtime, 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. Included in the java.lang.annotation package.

Use of annotations:

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 realize the function of replacing configuration files. For example, Dagger 2 dependency injection, which is very useful for java development in the future, will configure a large number of annotations; 3. Format check at compile time. If @ override is placed in front of the method, if your method does not override the superclass method, it can be checked during compilation.

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 we get annotations through reflection, we return the dynamic proxy object $Proxy1 generated by the Java runtime. Calling the method of custom annotation (Interface) through the proxy object will eventually call the invoke method of AnnotationInvocationHandler. This method will retrieve the corresponding value from the Map memberValues. The source of memberValues is the Java constant pool.

Meta annotation:

java.lang.annotation provides four meta annotations, specifically for other annotations (meta annotations need to be used when customizing annotations):

  • @Documented – will annotations be included in JavaDoc
  • @Retention – when to use this annotation
  • @Target – where are annotations used
  • @Inherited – whether subclasses are allowed to inherit the annotation

1.@Retention – defines the life cycle of the annotation

  • RetentionPolicy.SOURCE: discarded at compile time. These annotations no longer have any meaning after compilation, so they do not write bytecode@ Override and @ suppresswarnings belong to this type of annotation.
  • RetentionPolicy.CLASS: discarded when the class is loaded. It is useful in the processing of bytecode files. Annotations use this method by default
  • RetentionPolicy.RUNTIME: the annotation will never be discarded, and the annotation will be retained during the runtime. Therefore, the information of the annotation can be read using the reflection mechanism. Our custom annotations usually use this method.

2.Target – indicates where the annotation is used. The default value is any element, indicating where the annotation is used. Available ElementType parameters include

  • ElementType.CONSTRUCTOR: used to describe the constructor
  • ElementType.FIELD: member variables, objects, properties (including enum instances)
  • ElementType.LOCAL_VARIABLE: used to describe local variables
  • ElementType.METHOD: used to describe the method
  • ElementType.PACKAGE: used to describe the package
  • ElementType.PARAMETER: used to describe parameters
  • ElementType.TYPE: used to describe class, interface (including annotation type) or enum declaration

3.@Documented – a simple Annotations tag annotation indicating whether annotation information is added to the java document.

4.@Inherited – defines the relationship between the annotation and the subclass

@Inherited meta annotation is a tag annotation, @ inherited describes that a marked type is inherited. If an annotation type decorated with @ inherited is used for a class, the annotation will be used for the subclass of the class.

Annotation of common standards:

1.Override

java.lang.Override is a tag type annotation that is used as an annotation method. It shows that the marked method overloads the method of the parent class and plays the role of assertion. If we use this annotation, the java compiler will warn us of a compilation error when a method does not override the parent method.

2.Deprecated

Deprecated is also a tag type annotation. When a type or type member uses the @ deprecated modifier, the compiler will not encourage the use of the annotated program element. Therefore, using this modification has a certain "continuity": if we use this obsolete type or member in the code by inheritance or override, although the inherited or overridden type or member is not declared @ deprecated, the compiler still needs to alarm.

3.SuppressWarnings

SuppressWarning` Is not a tag type annotation. It has a type of`String[]` Member whose value is a prohibited warning name. about javac In terms of compiler, it is`-Xlint` The same applies to valid warning names for options`@SuppressWarings` Valid, and the compiler ignores unrecognized warning names.  `@SuppressWarnings("unchecked")

Custom annotation:

Some rules for writing custom annotation classes:

  1. Annotation type is defined as @ interface. All annotations will automatically inherit the java.lang.Annotation interface, and cannot inherit other classes or interfaces
  2. Parameter members can only be decorated with public or default access rights
  3. Parameter members can only use eight basic data types: byte, short, char, int, long, float, double and boolean, and data types such as String, Enum, Class and annotations, as well as arrays of these types
  4. To get the Annotation information of class methods and fields, you must obtain the Annotation object through Java reflection technology, because you have no other method to obtain the Annotation object
  5. Annotations can also have no defined members, but they are useless

PS: meta annotation is required for custom annotation

Custom annotation instance:

FruitName.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Fruit name notes
 */
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitName {
    String value() default "";
}
FruitColor.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * Fruit color notes
 */
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitColor {
    /**
     * Color enumeration
     */
    public enum Color{ BLUE,RED,GREEN};

    /**
     * color property
     */
    Color fruitColor() default Color.GREEN;

}
FruitProvider.java
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;


/**
 * Fruit supplier notes
 */
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitProvider {
    /**
     * Supplier number
     */
    public int id() default -1;

    /**
     * Supplier name
     */
    public String name() default "";

    /**
     * Supplier address
     */
    public String address() default "";
}
FruitInfoUtil.java
import java.lang.reflect.Field;

/**
 * annotation processor 
 */
public class FruitInfoUtil {
    public static void getFruitInfo(Class<?> clazz){

        String strFruitName=" Fruit Name:";
        String strFruitColor=" Fruit color:";
        String strFruitProvicer="Supplier information:";

        Field[] fields = clazz.getDeclaredFields();

        for(Field field :fields){
            if(field.isAnnotationPresent(FruitName.class)){
                FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
                strFruitName=strFruitName+fruitName.value();
                System.out.println(strFruitName);
            }
            else if(field.isAnnotationPresent(FruitColor.class)){
                FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
                strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
                System.out.println(strFruitColor);
            }
            else if(field.isAnnotationPresent(FruitProvider.class)){
                FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
                strFruitProvicer=" Supplier No.:"+fruitProvider.id()+" Supplier Name:"+fruitProvider.name()+" Supplier address:"+fruitProvider.address();
                System.out.println(strFruitProvicer);
            }
        }
    }
}
Apple.java
import test.FruitColor.Color;

/**
 * Annotation usage
 */
public class Apple {

    @FruitName("Apple")
    private String appleName;

    @FruitColor(fruitColor=Color.RED)
    private String appleColor;

    @FruitProvider(id=1,name="Shaanxi hongfuji group",address="Hongfuji building, 89 Yan'an Road, Xi'an, Shaanxi")
    private String appleProvider;

    public void setAppleColor(String appleColor) {
        this.appleColor = appleColor;
    }
    public String getAppleColor() {
        return appleColor;
    }

    public void setAppleName(String appleName) {
        this.appleName = appleName;
    }
    public String getAppleName() {
        return appleName;
    }

    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }
    public String getAppleProvider() {
        return appleProvider;
    }

    public void displayName(){
        System.out.println("The name of the fruit is apple");
    }
}
FruitRun.java
/**
 * Output results
 */
public class FruitRun {
    public static void main(String[] args) {
        FruitInfoUtil.getFruitInfo(Apple.class);
    }
}

reference resources

  1. Have you analyzed the implementation principle of Annotation?

Tags: Java

Posted on Wed, 01 Dec 2021 02:16:44 -0500 by nathanmaxsonadil