Как прочитать значение аннотации метода класса Java с помощью ASM

Как я могу прочитать значение аннотации метода Java во время выполнения с помощью ASM?
Аннотация имеет только CLASS RetentionPolicy, так что это невозможно сделать с отражениями.

| Политика CLASS: аннотации должны быть записаны компилятором в файл класса, но не должны сохраняться виртуальной машиной во время выполнения.

Пример.
Я хочу извлечь значение Carly Rae Jepsen из поля artist во время выполнения:

public class SampleClass {

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

    String artist() default "";
}

Но почему?
Нельзя ли просто изменить RetentionPolicy на RUNTIME и сделать это с отражениями?
Короче говоря: нет. Я использую modelmapper (простое, интеллектуальное, сопоставление объектов). Там я указываю двунаправленные сопоставления между классами Java с помощью аннотированных методов. Я не хочу повторно использовать эту информацию об иерархических сопоставлениях для распространения событий изменения. Но предоставленная аннотация mapstruct org.mapstruct.Mapping содержит CLASS RetentionPolicy. Вот почему мне нужно прочитать эту информацию из файлов классов — и мне нужен ASM.


person Tobse    schedule 14.05.2020    source источник


Ответы (1)


Есть много примеров, которые показывают установку с ассемблером и чтение аннотаций. Но они не показали это для аннотаций методов и того, как также читать значение аннотации.

Минимальный пример, как это сделать:

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

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

Будет напечатано:

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