JAVA Annotation

Note: Based on jdk11

Annotation package structure

Explanation of terms:

  • Meta annotation metadata annotation represents the annotation used to declare annotations
  • Marker annotation flag annotation indicates that there is no annotation for a member

Annotation

    
Annotation is a common interface implemented by all annotation types. However, if the interface is implemented by hard coding, it cannot define an annotation type. At the same time, the interface itself is not an annotation type. 
All annotation declaration formats are: @ interface annotation name {} implicitly indicates that a type (annotation type) implements the interface java.lang.annotation.Annotation
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

Target

Meta annotation refers to the syntax elements to which an annotation TYPE is applied. It is applied to all syntax elements except TYPE by default.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}

ElementType

The enumeration type represents the element context to which an annotation can be applied.
public enum ElementType {
    TYPE,
    FIELD,
    METHOD,
    PARAMETER,
    CONSTRUCTOR,
    LOCAL_VARIABLE,
    ANNOTATION_TYPE,
    PACKAGE,

    /**
     * Type parameter declaration
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     * @since 1.8
     */
    TYPE_USE,

    /**
     * Module declaration.
     * @since 9
     */
    MODULE
}

Retention

Meta annotation indicates that annotation type holds scope or lifecycle.
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

RetentionPolicy

The enumeration type represents the hold annotation cycle policy.
public enum RetentionPolicy { 
    SOURCE,//It is mainly used in source files for compile time check and discarded after check. 
    CLASS,//The default value, recorded by the compiler in the bytecode file, but not held by the runtime. 
    RUNTIME//In addition to being recorded by the compiler in a bytecode file, it can also be held by the runtime. See: java.lang.reflect. AnnotatedElement (indicating the annotated or annotated elements running in VM programs) 
} 

Inherited

Meta annotation is also a marker annotation indicating that an annotation type can be inherited 

Documented

Meta annotation is also a marker annotation indicating a type tag @ Documented annotation. Then all annotations on this type will be collected as part of the API by JAVA Doc 

Native

Meta annotation is also a marker annotation (sine 1.8), indicating that the value of a field reference may come from local code

Repeatable

meta-annotation(since1.8)

abnormal

AnnotationFormatError
AnnotationTypeMismatchException
IncompleteAnnotationException

Internal principles

To implement a simple orm Annotation to describe the internal principle of Java Annotation, the code is as follows:

source code

package chapter04;

import java.lang.annotation.*;

/**
 * a orm's table annotation
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

  String name() default "";
  String alias() default "";
}
package chapter04;

import java.lang.annotation.*;

/**
 * a orm's column annotation
 */
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    boolean primary() default false;
    String name() default "";
    String type() default "varchar";
    int length() default  0;
    String alias() default "";
}
package chapter04;

@Table(name = "t_student", alias = "s")
public class Student {

    @Column(primary = true, name = "_id", type = "bigint", length = 20)
    String id;
    @Column(name = "name", type = "string", length = 32)
    String name;
}
package chapter04;


public class TestAnno {

    public static void main(String [] args) throws NoSuchFieldException {

        System.setProperty("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true");

        Table table = Student.class.getAnnotation(Table.class);
        System.out.printf("table'name is %s, alias is %s. \n", table.name(), table.alias());

        Column column = Student.class.getDeclaredField("id").getAnnotation(Column.class);
        System.out.printf("column'name is %s, alias is %s. \n", column.name(), column.alias());

    }
}

By setting environment variables, you can save the code generated dynamically by jdk and view the configuration in the java.lang.reflect.ProxyGenerator class, as follows:

 /** debugging flag for saving generated class files */
    private static final boolean saveGeneratedFiles =
        java.security.AccessController.doPrivileged(
            new GetBooleanAction(
                "jdk.proxy.ProxyGenerator.saveGeneratedFiles")).booleanValue();

Agent code generated by jdk

package com.sun.proxy;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0 extends Proxy implements Retention {
    private static Method m1;
    private static Method m2;
    private static Method m4;
    private static Method m0;
    private static Method m3;

    public $Proxy0(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final RetentionPolicy value() throws  {
        try {
            return (RetentionPolicy)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("java.lang.annotation.Retention").getMethod("annotationType");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
            m3 = Class.forName("java.lang.annotation.Retention").getMethod("value");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
package com.sun.proxy;

import chapter04.Table;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy1 extends Proxy implements Table {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m5;
    private static Method m4;
    private static Method m0;

    public $Proxy1(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final String name() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String alias() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("chapter04.Table").getMethod("name");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m5 = Class.forName("chapter04.Table").getMethod("annotationType");
            m4 = Class.forName("chapter04.Table").getMethod("alias");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}
package com.sun.proxy;

import chapter04.Column;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy2 extends Proxy implements Column {
    private static Method m1;
    private static Method m7;
    private static Method m3;
    private static Method m4;
    private static Method m2;
    private static Method m8;
    private static Method m5;
    private static Method m6;
    private static Method m0;

    public $Proxy2(InvocationHandler var1) throws  {
        super(var1);
    }

    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }

    public final boolean primary() throws  {
        try {
            return (Boolean)super.h.invoke(this, m7, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String name() throws  {
        try {
            return (String)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String type() throws  {
        try {
            return (String)super.h.invoke(this, m4, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final Class annotationType() throws  {
        try {
            return (Class)super.h.invoke(this, m8, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int length() throws  {
        try {
            return (Integer)super.h.invoke(this, m5, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final String alias() throws  {
        try {
            return (String)super.h.invoke(this, m6, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m7 = Class.forName("chapter04.Column").getMethod("primary");
            m3 = Class.forName("chapter04.Column").getMethod("name");
            m4 = Class.forName("chapter04.Column").getMethod("type");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m8 = Class.forName("chapter04.Column").getMethod("annotationType");
            m5 = Class.forName("chapter04.Column").getMethod("length");
            m6 = Class.forName("chapter04.Column").getMethod("alias");
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}


As shown in the figure above, debug runs TestAnno, and with the agent class dynamically generated by jdk, the following conclusions can be drawn:


Table and Column are special interfaces that implement Annotation, while the dynamic proxy object $Proxy1 (the implementation class of table) and $Proxy2 (the implementation class of Column) generated by Java runtime are returned through reflection

Tags: Java JDK

Posted on Wed, 06 May 2020 07:00:50 -0400 by ankur0101