How to read a Java class method annotation value with ASM

放肆的年华 提交于 2020-12-12 04:28:29

问题


How can I read read the value of a Java method annotation at runtime with ASM ?
The Annotation has only a CLASS RetentionPolicy, so it's not possible to do that with Reflections.

| Policy CLASS: Annotations are to be recorded in the class file by the compiler but need not be retained by the VM at run time

Example:
I want to extract the value Carly Rae Jepsen out of the artist field at runtime:

public class SampleClass {

    @MyAnnotation(artist = "Carly Rae Jepsen")
    public void callMeMaybe(){}
}
@Documented
@Retention(RetentionPolicy.CLASS)
@Target(ElementType.METHOD)
public @interface MyAnnotation {

    String artist() default "";
}

But why?
Can't you just change the RetentionPolicy to RUNTIME and do it with reflections?
In short: No. I use the modelmapper framework (Simple, Intelligent, Object Mapping). There I specify bidirectional mappings between Java classes by annotated methods. I wan't to reuse this information of hierarchical mappings, for change event propagation. But the provided mapstruct org.mapstruct.Mapping Annotation has CLASS RetentionPolicy. This is why I need to read that information out of the class files - and need ASM.


回答1:


There are many samples which show the setup with asm and reading annotaions. But they don't showed it, for method annotations and how to also read the annotation value.

Minimal example how to do it:

import org.objectweb.asm.*;

public class AnnotationScanner extends ClassVisitor {
    public static void main(String[] args) throws Exception {
        ClassReader cr = new ClassReader(SampleClass.class.getCanonicalName());
        cr.accept(new AnnotationScanner(), 0);
    }

    public AnnotationScanner() {
        super(Opcodes.ASM8);
    }

    static class MyAnnotationVisitor extends AnnotationVisitor {
        MyAnnotationVisitor() {
            super(Opcodes.ASM8);
        }
        @Override
        public void visit(String name, Object value) {
            System.out.println("annotation: " + name + " = " + value);
            super.visit(name, value);
        }
    }

    static class MyMethodVisitor extends MethodVisitor {
        MyMethodVisitor() {
            super(Opcodes.ASM8);
        }
        @Override
        public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
            System.out.println("annotation type: " + desc);
            return new MyAnnotationVisitor();
        }
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
                                     String signature, String[] exceptions) {
        System.out.println("method: name = " + name);
        return new MyMethodVisitor();
    }
}

Maven dependecy

<dependency>
  <groupId>org.ow2.asm</groupId>
  <artifactId>asm</artifactId>
  <version>8.0.1</version>
</dependency>

It will print:

method: name = callMeMaybe
annotation type: Lorg/springdot/sandbox/asm/simple/asm/MyAnnotation;
annotation: artist = Carly Rae Jepsen


来源:https://stackoverflow.com/questions/61807758/how-to-read-a-java-class-method-annotation-value-with-asm

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!