Using ASM 5.0.4, I'm trying to find a class' fields and methods having a specific annotation. I like to avoid having to load the class to not worry about dependencies. So far, I can't figure out how to get a hold of the field/method annotations with this approach:
class AnnotationScanner extends ClassVisitor{
public AnnotationVisitor visitAnnotation(String desc, boolean visible){
System.out.println("visitAnnotation: desc="+desc+" visible="+visible);
return super.visitAnnotation(desc,visible);
}
public void visitAttribute(Attribute attr){
System.out.println("visitAttribute: attr="+attr);
super.visitAttribute(attr);
}
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value){
System.out.println("visitField: access="+access+" name="+name+" desc="+desc+" signature="+signature+" value="+value);
return super.visitField(access,name,desc,signature,value);
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions){
System.out.println("visitMethod: access="+access+" name="+name+" desc="+desc+" signature="+signature+" exceptions="+exceptions);
return super.visitMethod(access,name,desc,signature,exceptions);
}
public static void main(String[] args) throws Exception{
for (String arg : args){
FileInputStream in = new FileInputStream(new File(arg));
ClassReader cr = new ClassReader(in);
cr.accept(new AnnotationScanner(Opcodes.ASM4),0);
}
}
}
The entire sample project is on GitHub.
Running it against a simple class
@MyClass(name="annotation scanner")
public class Scannee{
@MyField(name="a string field") public String aStringField;
@MyMethod(name="a method") public void aMethod(){}
}
gives
visitAnnotation: desc=Lorg/springdot/sandbox/asm/MyClass; visible=true
visitField: access=1 name=aStringField desc=Ljava/lang/String; signature=null value=null
visitMethod: access=1 name=<init> desc=()V signature=null exceptions=null
visitMethod: access=1 name=aMethod desc=()V signature=null exceptions=null
but not the annotations of the field and the method.
How can I also get the field and method annotations?
You will need to subclass FieldVisitor and MethodVisitor and override the method visitAnnotation, similar to your ClassVisitor subclass. For example,
class FieldAnnotationScanner extends FieldVisitor {
public FieldAnnotationScanner() {
super(Opcodes.ASM5);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
System.out.println("visitAnnotation: desc="+desc+" visible="+visible);
return super.visitAnnotation(desc, visible);
}
}
class MethodAnnotationScanner extends MethodVisitor {
public MethodAnnotationScanner() {
super(Opcodes.ASM5);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
System.out.println("visitAnnotation: desc="+desc+" visible="+visible);
return super.visitAnnotation(desc, visible);
}
}
Then connect them to your AnnotationScanner in visitField and visitMethod. For example, change your code to
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value){
System.out.println("visitField: access="+access+" name="+name+" desc="+desc+" signature="+signature+" value="+value);
return new FieldAnnotationScanner();
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions){
System.out.println("visitMethod: access="+access+" name="+name+" desc="+desc+" signature="+signature+" exceptions="+exceptions);
return new MethodAnnotationScanner();
}
The example doesn't show how tho access the name value of the @MyMethod annotation (name="a method"). To also read the a method value, you have to add two more Visitors:
static class MethodAnnotationScanner extends MethodVisitor {
MethodAnnotationScanner() {
super(Opcodes.ASM8);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
System.out.println("visitMethodAnnotation: type= " + desc);
return new MyAnnotationVisitor();
}
}
static class MethodAnnotationValueScanner extends AnnotationVisitor {
MethodAnnotationValueScanner() {
super(Opcodes.ASM8);
}
@Override
public void visit(String name, Object value) {
System.out.println("visitMethodAnnotationValue: " + name + " = " + value);
super.visit(name, value);
}
}
And insert them by changing retruning the MethodAnnotationScanner int the visitMethod:
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
System.out.println("visitMethod: access="+access+" name="+name+" desc="+desc+" signature="+signature+" exceptions="+exceptions);
return new MethodAnnotationScanner();
}
You can see the full updated example here: how-to-read-a-java-class-method-annotation-value-with-asm
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With