Sunday, 3 May 2020

Javassist: Add an annotation to a run time generated method

Follow below steps to add annotation to a run time method.

Step 1: Define annotation.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Logger {
         String value();
}

Step 2: Get an instance of ClassPool
ClassPool classPool = ClassPool.getDefault();

Step 3: Create a class and get ClassFile and ConstPool references
CtClass ctClass = classPool.makeClass("com.sample.App.Test");
ClassFile classFile = ctClass.getClassFile();
ConstPool constPool = classFile.getConstPool();

Step 4: Create AnnotationsAttribute
AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool,AnnotationsAttribute.visibleTag);
Annotation annotation = new Annotation("com.sample.app.annotations.Logger", constPool);
annotation.addMemberValue("value", new StringMemberValue("ERROR", constPool));
annotationsAttribute.addAnnotation(annotation);

Step 5: Create new Method object.
CtMethod ctMethod = CtNewMethod.make(Modifier.PUBLIC, CtClass.doubleType, "getPI", null, null, "return 3.14;", ctClass);

Step 6: Add annotation to the method.
ctMethod.getMethodInfo().addAttribute(annotationsAttribute);

Step 7: Add method to the class.
ctClass.addMethod(ctMethod);

Find the below working application.

Logger.java
package com.sample.app.annotations;

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

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface Logger {
 String value();
}

App.java
package com.sample.app;

import java.lang.reflect.Modifier;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.bytecode.AnnotationsAttribute;
import javassist.bytecode.ClassFile;
import javassist.bytecode.ConstPool;
import javassist.bytecode.annotation.Annotation;
import javassist.bytecode.annotation.StringMemberValue;

public class App {

 public static void main(String args[]) throws Exception {
  ClassPool classPool = ClassPool.getDefault();

  // create a class and get ClassFile and ConstPool references
  CtClass ctClass = classPool.makeClass("com.sample.App.Test");
  ClassFile classFile = ctClass.getClassFile();
  ConstPool constPool = classFile.getConstPool();

  // create the annotation
  AnnotationsAttribute annotationsAttribute = new AnnotationsAttribute(constPool,
    AnnotationsAttribute.visibleTag);
  Annotation annotation = new Annotation("com.sample.app.annotations.Logger", constPool);
  annotation.addMemberValue("value", new StringMemberValue("ERROR", constPool));
  annotationsAttribute.addAnnotation(annotation);

  CtMethod ctMethod = CtNewMethod.make(Modifier.PUBLIC, CtClass.doubleType, "getPI", null, null, "return 3.14;",
    ctClass);
  // Add annotation to the method.
  ctMethod.getMethodInfo().addAttribute(annotationsAttribute);
  
  // Add method to the class
  ctClass.addMethod(ctMethod);

  // Add annotation to the class.
  // classFile.addAttribute(annotationsAttribute);

  ctClass.writeFile("/Users/Shared/javassist");
 }
}

Run App.java.

When you go to the directory /Users/Shared/javassist, you can see that Test.class file is created.

$tree /Users/Shared/javassist/
/Users/Shared/javassist/
└── com
    └── sample
        └── App
            └── Test.class

3 directories, 1 file

Open Test.class file in java de-compiler to see the source code.

From the source code, you can confirm Logger annotation is added to getPI method.


Previous                                                    Next                                                    Home

No comments:

Post a Comment