利用Javassist动态添加标签Annotations(英文)

How to add Annotations at Runtime to a java class method using Javassist?

Annotations are a new feature from Java 5. Annotations are a kind of comment or meta data you can insert in your Java code. But how can we add them dynamically at runtime to the java class since the jdk doesn’t provide any addAnnotation method ?
 
 
Introduction
Java annotations were introduced in 2002 through the JCP (JSR-175) and were approved inSeptember 2004 as an alternative to the configuration xml files. Java annotations, can (if necessary) be accessible to the programmer at the runtime through reflection api.

How to scan java annotations?
 
The easiest way to scan through a resource is to load it through a Classloader and use the Java Reflection API to look for the specified annotation. However, this approach will only help you to find annotations that are visible at runtime @Retention (value = RetentionPolicy.RUNTIME), and loading each resource into memory will consume an unnecessary amount of memory.
 
Lets create a simple annotation, annotations are defined like interfaces. Here is the @PersonneName definition:
package sample;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Retention(value = RetentionPolicy.RUNTIME)  //The annotation is saved in the*.class and can be used by the JVM.     
@Target(value = ElementType.METHOD)  //The annotation can be used on methods.
public @interface PersonneName {
public String name();
}

let's now create a simple SayHelloBean on wich we will apply this simple annotation

package sample;
import java.lang.reflect.Method;
import sample.PersonneName;
 
public class SayHelloBean {
  
private static final  String HELLO_MSG = "Hello ";
 
@PersonneName(name="World !! (simple annotation)")
public String sayHelloTo(String name){
 return HELLO_MSG+name;
}
 
public static void main(String[] args) {
  
  
   try{
    //instanciate the bean
    SayHelloBean simpleBean  = new SayHelloBean(); 
    //get the method descriptor through reflection
          Method helloMessageMethod = simpleBean.getClass().getDeclaredMethod("sayHelloTo", String.class); 
          //scan the annotation
          PersonneName mySimpleAnnotation = (PersonneName) helloMessageMethod.getAnnotation(PersonneName.class);
           
          System.out.println(simpleBean.sayHelloTo(mySimpleAnnotation.name()));
      }
      catch(Exception e){
          e.printStackTrace();
      }
}
}
Runing the main method produce : Hello World !! (simple annotation)

 
How to add Annotations dynamically at Runtime to a java class method?
Why ?
 
  • Jdk doesn’t provide an addAnnotation method through reflection.
  • Sometimes we need to define annotation dynamically at runtime (example of jsr 303 validation annotations )
  • Add new behaviors to your classes 
How ?
 
We will use Javassist (Java Programming Assistant) . It is a class library for editing bytecodes in Java; it enables Java programs to define a new class at runtime and to modify a class file when the JVM loads it. (More informations and downloads here javassist ).
 
Now let’s modify the preceding example to add the @PersonneName at runtime to the SayHelloBean,first we will delete the annotation from the SayHelloBean code
 
package sample;
 
public class SayHelloBean {
  
private static final  String HELLO_MSG = "Hello ";
 
public String sayHelloTo(String name){
 return HELLO_MSG+name;
}
}

second we create the class AddRunTimeAnnotation that will add the annotation dynamically to the SayHelloBean class :

package sample;
import java.lang.reflect.Method;
 
import sample.PersonneName;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;
 
 
 
 
public class AddRunTimeAnnotation {
  
  public static void addPersonneNameAnnotationToMethod(String className,String methodName) throws Exception{
    
 //pool creation 
 ClassPool pool = ClassPool.getDefault();
 //extracting the class
 CtClass cc = pool.getCtClass(className);
 //looking for the method to apply the annotation on
 CtMethod sayHelloMethodDescriptor = cc.getDeclaredMethod(methodName);
 // create the annotation
 ClassFile ccFile = cc.getClassFile();
 ConstPool constpool = ccFile.getConstPool();
 AnnotationsAttribute attr = new AnnotationsAttribute(constpool, AnnotationsAttribute.visibleTag);
 Annotation annot = new Annotation("sample.PersonneName", constpool);
 annot.addMemberValue("name", new StringMemberValue("World!! (dynamic annotation)",ccFile.getConstPool()));
 attr.addAnnotation(annot);
 // add the annotation to the method descriptor
 sayHelloMethodDescriptor.getMethodInfo().addAttribute(attr);
  
  
 // transform the ctClass to java class
 Class dynamiqueBeanClass = cc.toClass();
 //instanciating the updated class 
 SayHelloBean sayHelloBean = (SayHelloBean) dynamiqueBeanClass.newInstance();
  
  try{
   
         Method helloMessageMethod = sayHelloBean.getClass().getDeclaredMethod(methodName, String.class);  
         //getting the annotation
         PersonneName personneName = (PersonneName) helloMessageMethod.getAnnotation(PersonneName.class);
         System.out.println(sayHelloBean.sayHelloTo(personneName.name()));
     }
     catch(Exception e){
         e.printStackTrace();
     }
  
 
}
public static void main(String[] args) {
  
 try {
  AddRunTimeAnnotation.addPersonneNameAnnotationToMethod("sample.SayHelloBean", "sayHelloTo");
 } catch (Exception e) {
  
  e.printStackTrace();
 }
  
}
}
Runing the main method now produce : Hello World!! (dynamic annotation).
 
Looking ahead
There's a lot more to Javassist than what we've covered in this article. Javassist  enables Java programs to define a new class at runtime and to modify a class file before the JVM loads it. Unlike other similar systems, Javassist provides source-level abstraction; programmers can modify a class file without detailed knowledge of the Java bytecode.start enjoying it :).
posted @ 2014-01-10 22:43  寂静沙滩  阅读(2403)  评论(0编辑  收藏  举报