How does java annotation annotation use and reflection get annotations

  • 2020-05-30 20:06:15
  • OfStack

1. Annotate the basics

1. Meta notes

Meta-annotations are annotations of annotations. Including @Retention @Target @Document @Inherited4.

1. Type Annotation is defined as @interface. All Annotation automatically inherit the java.lang.Annotation interface and cannot inherit other classes or interfaces.

2. Parameter members can only be decorated with the two access rights public or the default (default)

3. Members can only use basic types byte parameters, short, char, int, long, float, double, boolean8 basic data types and String, Enum, Class, annotations, such as data types, and the 1 some type of the array.

4. To get annotation information for class methods and fields, you must use Java's reflection technique to get Annotation objects, because you have no other way to get annotation objects

5. Annotations can also have no members defined, but they are useless

When defining a custom annotation class, you can specify the target (class, method, field, constructor, etc.), the lifecycle of the annotation (valid at runtime in class files or source code), whether to include the annotation in javadoc, and whether to allow subclasses to inherit the annotation from the parent class, as follows:

1. @Target represents the annotation target, and possible ElemenetType parameters include:


ElemenetType.CONSTRUCTOR  Constructor declaration 
ElemenetType.FIELD  The domain statement ( including  enum  The instance ) 
ElemenetType.LOCAL_VARIABLE  Local variable declaration  
ElemenetType.METHOD  Method statement  
ElemenetType.PACKAGE  Package declaration  
ElemenetType.PARAMETER  Parameter declarations  
ElemenetType.TYPE  Classes and interfaces ( Including annotation types ) or enum The statement 

2. @Retention indicates the lifecycle of the annotation, and the optional RetentionPolicy parameters include


RetentionPolicy.SOURCE  Annotations are discarded by the compiler  
RetentionPolicy.CLASS  Annotations in class Available in file, but will be VM discarded  
RetentionPolicy.RUNTIME VM Annotations are also retained at run time, so they can be read through a reflection mechanism 

3. @Documented indicates that this annotation is included in javadoc

4. The @Inherited directive allows subclasses to inherit annotations from their parent classes

2. How is it used in java

2.1. Define annotations


package com.test.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


public class MyAnnotation {
  
  /**
   *  Annotation class 
   * @author T4980D
   *
   */
  @Retention(RetentionPolicy.RUNTIME) 
  @Target(ElementType.TYPE) 
  public @interface MyClassAnnotation { 
    String uri(); 
    String desc(); 
  } 
  
  /** 
   *  Construction annotation  
   * @author T4980D 
   * 
   */ 
  @Retention(RetentionPolicy.RUNTIME)   
  @Target(ElementType.CONSTRUCTOR)  
  public @interface MyConstructorAnnotation { 
   
    String uri(); 
    String desc(); 
  } 
  
  /** 
   *  My method notes  
   * @author Owner 
   * 
   */ 
  @Retention(RetentionPolicy.RUNTIME)   
  @Target(ElementType.METHOD) 
  public @interface MyMethodAnnotation { 
   
    String uri(); 
    String desc(); 
  } 
  
  /** 
   *  Field annotation definition  
   * @author Owner 
   * 
   */ 
  @Retention(RetentionPolicy.RUNTIME)   
  @Target(ElementType.FIELD)  
  public @interface MyFieldAnnotation { 
   
    String uri(); 
    String desc(); 
  } 
  /**
   * 
   *  You can apply to both classes and methods 
   * @author T4980D
   *
   */
  @Target({ElementType.TYPE, ElementType.METHOD})
  @Retention(RetentionPolicy.RUNTIME)
  public @interface Yts {
    //  Define the enumeration 
    public enum YtsType {
      util, entity, service, model
    }

    //  Set default values 
    public YtsType classType() default YtsType.util;
    
    //  An array of 
    int[] arr() default {3, 7, 5};

    String color() default "blue";
  }
    
}

2.2 basic test notes


package com.test.annotation;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import com.test.annotation.MyAnnotation.MyClassAnnotation;
import com.test.annotation.MyAnnotation.MyConstructorAnnotation;
import com.test.annotation.MyAnnotation.MyFieldAnnotation;
import com.test.annotation.MyAnnotation.MyMethodAnnotation;
import com.test.annotation.MyAnnotation.Yts;
import com.test.annotation.MyAnnotation.Yts.YtsType;

@MyClassAnnotation(desc = "The class", uri = "com.test.annotation.Test")
@Yts(classType =YtsType.util)
public class TestAnnotation {
  @MyFieldAnnotation(desc = "The class field", uri = "com.test.annotation.Test#id")
  private String id;

  @MyConstructorAnnotation(desc = "The class constructor", uri = "com.test.annotation.Test#MySample")
  public TestAnnotation() {
  }

  public String getId() {
    return id;
  }

  @MyMethodAnnotation(desc = "The class method", uri = "com.test.annotation.Test#setId")
  public void setId(String id) {
    System.out.println(" method info: "+id);
    this.id = id;
  }
  
  @MyMethodAnnotation(desc = "The class method sayHello", uri = "com.test.annotation.Test#sayHello")
  @Yts 
  public void sayHello(String name){ 
    if(name == null || name.equals("")){ 
      System.out.println("hello world!"); 
    }else{ 
      System.out.println(name + "\t:say hello world!"); 
    } 
  } 
  public static void main(String[] args) throws Exception {

    Class<TestAnnotation> clazz = TestAnnotation.class;
    //  Get class annotations 
    MyClassAnnotation myClassAnnotation = clazz.getAnnotation(MyClassAnnotation.class);
    System.out.println(myClassAnnotation.desc() + " "+ myClassAnnotation.uri());

    //  Get the constructor annotation 
    Constructor<TestAnnotation> cons = clazz.getConstructor(new Class[]{});
    MyConstructorAnnotation myConstructorAnnotation = cons.getAnnotation(MyConstructorAnnotation.class);
    System.out.println(myConstructorAnnotation.desc() + " "+ myConstructorAnnotation.uri());

    //  Get method annotation 
    Method method = clazz.getMethod("setId", new Class[]{int.class});
    MyMethodAnnotation myMethodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
    System.out.println(myMethodAnnotation.desc() + " "+ myMethodAnnotation.uri());
    //  Get field annotations 
    Field field = clazz.getDeclaredField("id");
    MyFieldAnnotation myFieldAnnotation = field.getAnnotation(MyFieldAnnotation.class);
    System.out.println(myFieldAnnotation.desc() + " "+ myFieldAnnotation.uri());
  }

}

2.3 analysis by reflection


package com.test.annotation;

import java.lang.reflect.Method;
import java.util.Arrays;

import com.test.annotation.MyAnnotation.MyClassAnnotation;
import com.test.annotation.MyAnnotation.MyMethodAnnotation;
import com.test.annotation.MyAnnotation.Yts;
import com.test.annotation.MyAnnotation.Yts.YtsType;

public class ParseAnnotation {

  /**
   *  Parsing method annotation 
   * @param <T>
   * @param clazz
   */
  public static <T> void parseMethod(Class<T> clazz) {
    try {
      T obj = clazz.newInstance();
      for (Method method : clazz.getDeclaredMethods()) {
        MyMethodAnnotation methodAnnotation = method.getAnnotation(MyMethodAnnotation.class);
        if (methodAnnotation!=null) {
          // The method with this annotation is called by reflection 
          method.invoke(obj, methodAnnotation.uri());
        }
        Yts yts = (Yts) method.getAnnotation(Yts.class);
        if (yts != null) {
          if (YtsType.util.equals(yts.classType())) {
            System.out.println("this is a util method");
          } else {
            System.out.println("this is a other method");
          }
          System.out.println(Arrays.toString(yts.arr())); // Print the array 
          System.out.println(yts.color()); // The output color 
        }
        System.out.println("\t\t-----------------------");
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   *  Parse class annotation 
   * @param <T>
   * @param clazz
   */
  public static <T> void parseType(Class<T> clazz) {
    try {
      Yts yts = (Yts) clazz.getAnnotation(Yts.class);
      if (yts != null) {
        if (YtsType.util.equals(yts.classType())) {
          System.out.println("this is a util class");
        } else {
          System.out.println("this is a other class");
        }
      }
      MyClassAnnotation classAnnotation = (MyClassAnnotation) clazz.getAnnotation(MyClassAnnotation.class);
      if (classAnnotation != null) {
        System.err.println(" class info: "+classAnnotation.uri());
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  
  public static void main(String[] args) {
    parseMethod(TestAnnotation.class);
    parseType(TestAnnotation.class);
  }

}

3. Annotate application cases

3.1 regarding fine-grained authority interception, any of the 11 action methods can be intercepted according to the authority of the login user in Struts2, and a custom method annotation can be defined, for example


@Retention(RetentionPolicy.RUNTIME)// On behalf of Permission The comment remains in the stage  
@Target(ElementType.METHOD)// Labeled above the method  
public @interface Permission { 
 
  /**  The module  */ 
  String module(); 
  /**  Permission values  */ 
  String privilege(); 
   
} 

3, 2 for example, there is a department action, Department. action, there is a method public String departmentlistUI(){} can be defined in this way


@Permission(module="department",privilege="view") 
public String departmentlistUI(){ 

} 

3.3. Then define a permission interceptor PrivilegeInterceptor.java and register it in struts.xml. After the implementation of interceptor interface, the implementation method public String intercept(ActionInvocation invocation) throws Exception {}. This code gets the action name and method name.


String actionName=invocation.getProxy().getActionName(); 
String methodName=invocation.getProxy().getMethod(); 
     
System.out.println(" Intercepted: action Name: "+actionName+" The method name: "+methodName); 

4. Then, through reflection technology, get the custom permission annotation on this method, get the user who is currently logged in (from session), traverse the permission group owned by the current user, and traverse all the permissions under any one permission group to see whether the required permissions for annotation on this method are included. This allows fine-grained interception of action method permissions.


private boolean validate(ActionInvocation invocation) throws SecurityException, NoSuchMethodException { 
     
    String methodName=invocation.getProxy().getMethod(); 
     
    Method currentMethod = invocation.getAction().getClass().getMethod(methodName); 
     
    if(currentMethod != null && currentMethod.isAnnotationPresent(Permission.class)){ 
      // Get a comment on the method  
      Permission permission = currentMethod.getAnnotation(Permission.class); 
      // The required permissions on this method  
      SystemPrivilege methodPrivilege = new SystemPrivilege(new SystemPrivilegePK(permission.module(), permission.privilege())); 
      // Gets the user currently logged in  
      Employee e = (Employee) ActionContext.getContext().getSession().get("loginUser"); 
      // Traverses all permission groups under the current user  
      for(PrivilegeGroup group : e.getGroups()){ 
        // If the permission group contains the permissions needed to access the method, release it  
        if(group.getPrivileges().contains(methodPrivilege)){ 
          return true; 
        } 
         
      } 
      // Indicates that the traversal of all the permission groups of the user, the permission was not found, indicating that the permission is not available  
      return false; 
        
    } 
    // There is no annotation to indicate that anyone can call the method  
    return true; 
  } 

Thank you for reading, I hope to help you, thank you for your support of this site!


Related articles: