简体   繁体   中英

How to read a Java class method annotation value with ASM

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 .

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM