Details the use of Java annotation objects in Java programming

  • 2020-05-07 19:33:52
  • OfStack

Annotations (also known as metadata) provide a formalized way for us to add information to our code, making it easy to use at a later point in time.
 
1. Basic syntax
Three standard annotations are built into Java SE5
Override: indicates that the current method definition overrides the method in the superclass. If you accidentally misspell or the method signature is not overridden
Cover method, the compiler will issue an error message
Deprecated: the compiler will issue a warning if the programmer USES an element annotated to it
SupperessWarnings: turn off improper compiler warnings.
Four meta-annotations are built into Java SE5
Target: indicates where the annotation can be used. Possible ElementType parameters include:
1)CONSTRUCTOR: constructor declaration
2)FIELD: domain declarations (including enum instances)
3)LOCAL_VARIABLE: local variable declaration
4)METHOD: method declaration
5) PACKAGE: package declaration
6)PARAMETER: parameter declaration
7)TYPE: class, interface (including annotation type) or enum declaration
Retention: indicates at what level the annotation information needs to be saved. Optional RetentionPolicy parameters include:
1)SOURCE: annotations will be discarded by the compiler
2)CLASS: annotations are available in class files, but are discarded by VM
3)RUNTIME:VM will also retain annotations at run time, so the information of the annotations can be read through the reflection mechanism
Documented: include this annotation in Javadoc
Inherited: allows subclasses to inherit annotations from parent classes
Most of the time, programmers define their own annotations and write their own processors to handle them.
UseCase.java      


package com;  
 
import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  
 
@Target(ElementType.METHOD)// Where will your annotations be applied , This office applies the method   
// Where is the annotation used to define it 1 Levels available , In the source code (source) Class file (class) Or runtime (runtime)  
@Retention(RetentionPolicy.RUNTIME)  
public @interface UseCase {  
 public int id();  
 public String description()default "no description";  
}  
 
 PasswordUtils .java  
package com;  
 
public class PasswordUtils {  
 @UseCase(id=47,description="Passwords must contain at least one numeric")  
 public boolean validatePassword(){  
 return true;  
 }  
  
 @UseCase(id=48)  
 public String encryptPassword(String password){  
 return password;  
 }  
  
 @UseCase(id=49,description="Jong_Cai")  
 public void showName(){  
 System.out.println("Jong_Cai");  
 }  
}  

 
2. Write an annotation handler
Annotations are no more useful than annotations if there is no tool for reading them
Is to create and use annotations processor. Java API SE5 expanded the reflection mechanism, in order to help programmers to construct this kind of tool. At the same time, it also provides an external tool apt help programmers parsing Java source code with annotations. Below is a very simple annotation processor, we will use it to read PasswordUtils class, and the use of reflection mechanism to find @ UseCase tag. We provide 1 set of id worth it, then it will list the use cases, found in PasswordUtils and missing cases.


 UseCaseTracker.java 
package com;  
 
import java.lang.reflect.Method;  
import java.util.ArrayList;  
import java.util.Collections;  
import java.util.List;  
 
public class UseCaseTracker {  
 public static void trackUseCases(List<Integer> list, Class<?> cl) {  
 for (Method m : cl.getDeclaredMethods()) {  
  UseCase us = m.getAnnotation(UseCase.class);  
  if (us != null) {  
  System.out.println("Found Use Case:" + us.id() + " " 
   + us.description());  
  list.remove(new Integer(us.id()));  
  }  
 }  
 for (int i : list) {  
  System.out.println("Warning:Missing use case-" + i);  
 }  
 }  
 
 public static void main(String[] args) {  
 List<Integer> list = new ArrayList<Integer>();  
 Collections.addAll(list, 47,48,49,50,51);  
 trackUseCases(list, PasswordUtils.class);  
 }  
}  

 
This program with the help of two methods: reflection getDeclaredMethods () and getAnnotation (), they all belong to AnnotatedElement interface (class, Method and Field classes implement this interface). getAnnotation () method returns the specified type annotation object, is UseCase here, if the annotation method without the type annotation, it returns null value. Then we by calling id () and description () method of extracting elements from the returned UseCase object value. The encryptPassword () method The value of description is not specified in the annotation, so the processor gets the default value no description through the description() method when processing its corresponding annotation.

Annotation in the world of java is overwhelming, free to write a simple annotations article, is about the introduction of Annotation article, I hope you can throw bricks, learn together...
Don't talk nonsense, practice is the hard truth.

3. Instance
let's talk about the concept of annotation first, and then let's talk about how to design annotation.
First, open the following source files in the java.lang.annotation package that comes with jdk:
   
The source file Target java


@Documented 
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.ANNOTATION_TYPE)  
public @interface Target {  
  ElementType[] value();  

@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.ANNOTATION_TYPE) 
public @interface Target { 
  ElementType[] value(); 
} 

   
The @interface is a keyword, so when designing annotations, you must define a type as @interface, instead of class or interface.
   
The source file Retention java


@Documented 
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.ANNOTATION_TYPE)  
public @interface Retention {  
  RetentionPolicy value();  
} 

@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.ANNOTATION_TYPE) 
public @interface Retention { 
  RetentionPolicy value(); 
} 


See here, you may not know what to say, don't worry, look down 1. In the above files are used RetentionPolicy, ElementType these two fields, you may guess that this is the two java files.
   
The source file RetentionPolicy java


public enum RetentionPolicy {  
 SOURCE,  
 CLASS,  
 RUNTIME  
} 

public enum RetentionPolicy { 
 SOURCE, 
 CLASS, 
 RUNTIME 
} 

This is one enum type with three values, SOURCE,CLASS and RUNTIME.
SOURCE means that the information of Annotation type will only be kept in the source code of the program. If the source code is compiled, the data of Annotation will disappear and will not be kept in the compiled class file.
ClASS means that the Annotation information is kept in the source code of the program, but also in the compiled class file, which is not loaded into the virtual machine (JVM) during execution.
The third, RUNTIME, holds information in the source, compiled.class file, which is loaded into JVM during execution.
For example, if Retention in @Override is set to SOURCE, it will be compiled successfully without any checking information. In contrast, Retention in @Deprecated is set to RUNTIME, which means that in addition to warning us which method is Deprecated used at compile time, we can also find out whether the method is Deprecated at execution time.


The source file ElementType java


public enum ElementType {  
 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR,  
 LOCAL_VARIABLE, ANNOTATION_TYPE,PACKAGE  
} 

public enum ElementType { 
 TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, 
 LOCAL_VARIABLE, ANNOTATION_TYPE,PACKAGE 
} 

ElementType in     @ Target is used to specify which elements the Annotation type can be used on. TYPE(type), FIELD(property), METHOD(method), PARAMETER(parameter), CONSTRUCTOR(constructor),LOCAL_VARIABLE(local variable), ANNOTATION_TYPE,PACKAGE(package), ANNOTATION_TYPE (type) refers to the Class,Interface,Enum and Annotation types.
    in addition, from the source code of 1, it can be seen that @Target also USES itself to declare itself, which can only be used on ANNOTATION_TYPE.
    if an Annotation type does not specify which elements @Target is used on, then it can be used on any element, which in this case refers to the eight types above.
    to give you a few good examples:
    @Target(ElementType.METHOD)
    @Target(value=ElementType.METHOD)
    @Target(ElementType.METHOD,ElementType.CONSTRUCTOR)    
    refer to javadoc documentation for details
   
    source files all use @Documented. The purpose of @Documented is to enable the information of Annotation type to be displayed on the javaAPI documentation. Without the addition, the information generated by this type will not be found when using javadoc to generate the API document.
    another point, if you want to inherit the Annotation data to a subclass, you will use the @Inherited Annotation type.  
     
The following is a simple example of Annotation, which USES four files.  
Description.java


package lighter.javaeye.com;  
 
import java.lang.annotation.Documented;  
import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  
 
@Target(ElementType.TYPE)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented 
public @interface Description {  
  String value();  
} 

package lighter.javaeye.com; 
 
import java.lang.annotation.Documented; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
@Target(ElementType.TYPE) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface Description { 
  String value(); 
} 

   
Note: all Annotation will automatically inherit java.lang.annotation, so you cannot inherit any other classes or interfaces.
The most important point is how to set the parameters in Annotation:
First, you can only use the two access rights, public or the default (default). For example,String value(); The method is set to the defaul default type.
2, members can only use basic types byte parameters, short, char, int, long, float, double, boolean8 basic data types and String Enum, Class, annotations data such as types, and the more types of arrays. For example, String value (); The parameter member here is String.
Third, if there is only one parameter member, it is best to set the parameter name to "value", followed by parentheses.

Name.java


package lighter.javaeye.com;  
 
import java.lang.annotation.Documented;  
import java.lang.annotation.ElementType;  
import java.lang.annotation.Retention;  
import java.lang.annotation.RetentionPolicy;  
import java.lang.annotation.Target;  
 
// Notice the @Target with @Description What is the different , Parameter members are also different   
@Target(ElementType.METHOD)  
@Retention(RetentionPolicy.RUNTIME)  
@Documented 
public @interface Name {  
  String originate();  
  String community();  
} 

package lighter.javaeye.com; 
 
import java.lang.annotation.Documented; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
// Notice the @Target with @Description What is the different , Parameter members are also different  
@Target(ElementType.METHOD) 
@Retention(RetentionPolicy.RUNTIME) 
@Documented 
public @interface Name { 
  String originate(); 
  String community(); 
} 


JavaEyer.java


package lighter.javaeye.com;  
 
@Description("javaeye, Be the best software development community ")  
public class JavaEyer {  
  @Name(originate=" The founder of :robbin",community="javaEye")  
  public String getName()  
  {  
    return null;  
  }  
    
  @Name(originate=" The founder of : Jiangnan white ",community="springside")  
  public String getName2()  
  {  
    return " Borrow two id1 with , I write this 1 An example , Please forgive me !";  
  }  
} 


package lighter.javaeye.com; 
 
@Description("javaeye, Be the best software development community ") 
public class JavaEyer { 
  @Name(originate=" The founder of :robbin",community="javaEye") 
  public String getName() 
  { 
    return null; 
  } 
   
  @Name(originate=" The founder of : Jiangnan white ",community="springside") 
  public String getName2() 
  { 
    return " Borrow two id1 with , I write this 1 An example , Please forgive me !"; 
  } 
} 

Write a class TestAnnotation that can run to extract JavaEyer information

 


package lighter.javaeye.com;  
 
 import java.lang.reflect.Method;  
 import java.util.HashSet;  
 import java.util.Set;  
 
 public class TestAnnotation {  
  /** 
   * author lighter 
   *  instructions : Specific about Annotation the API See also javaDoc The document  
   */ 
    public static void main(String[] args) throws Exception {  
    String CLASS_NAME = "lighter.javaeye.com.JavaEyer";  
    Class test = Class.forName(CLASS_NAME);  
    Method[] method = test.getMethods();  
    boolean flag = test.isAnnotationPresent(Description.class);  
    if(flag)  
    {  
      Description des = (Description)test.getAnnotation(Description.class);  
      System.out.println(" describe :"+des.value());  
      System.out.println("-----------------");  
    }  
      
    // the JavaEyer this 1 Class is useful for @Name Save all methods to Set in   
    Set<Method> set = new HashSet<Method>();  
    for(int i=0;i<method.length;i++)  
    {  
      boolean otherFlag = method[i].isAnnotationPresent(Name.class);  
      if(otherFlag) set.add(method[i]);  
    }  
    for(Method m: set)  
    {  
      Name name = m.getAnnotation(Name.class);  
      System.out.println(name.originate());  
      System.out.println(" Created communities :"+name.community());  
    }  
   }  
} 

 package lighter.javaeye.com; 
 
 import java.lang.reflect.Method; 
 import java.util.HashSet; 
 import java.util.Set; 
 
 public class TestAnnotation { 
  /** 
   * author lighter 
   *  instructions : Specific about Annotation the API See also javaDoc The document  
   */ 
    public static void main(String[] args) throws Exception { 
    String CLASS_NAME = "lighter.javaeye.com.JavaEyer"; 
    Class test = Class.forName(CLASS_NAME); 
    Method[] method = test.getMethods(); 
    boolean flag = test.isAnnotationPresent(Description.class); 
    if(flag) 
    { 
      Description des = (Description)test.getAnnotation(Description.class); 
      System.out.println(" describe :"+des.value()); 
      System.out.println("-----------------"); 
    } 
     
    // the JavaEyer this 1 Class is useful for @Name Save all methods to Set in  
    Set<Method> set = new HashSet<Method>(); 
    for(int i=0;i<method.length;i++) 
    { 
      boolean otherFlag = method[i].isAnnotationPresent(Name.class); 
      if(otherFlag) set.add(method[i]); 
    } 
    for(Method m: set) 
    { 
      Name name = m.getAnnotation(Name.class); 
      System.out.println(name.originate()); 
      System.out.println(" Created communities :"+name.community()); 
    } 
   } 
} 

Operation results:


 UseCaseTracker.java 
package com;  
 
import java.lang.reflect.Method;  
import java.util.ArrayList;  
import java.util.Collections;  
import java.util.List;  
 
public class UseCaseTracker {  
 public static void trackUseCases(List<Integer> list, Class<?> cl) {  
 for (Method m : cl.getDeclaredMethods()) {  
  UseCase us = m.getAnnotation(UseCase.class);  
  if (us != null) {  
  System.out.println("Found Use Case:" + us.id() + " " 
   + us.description());  
  list.remove(new Integer(us.id()));  
  }  
 }  
 for (int i : list) {  
  System.out.println("Warning:Missing use case-" + i);  
 }  
 }  
 
 public static void main(String[] args) {  
 List<Integer> list = new ArrayList<Integer>();  
 Collections.addAll(list, 47,48,49,50,51);  
 trackUseCases(list, PasswordUtils.class);  
 }  
}  
0



Related articles: