4

I want to use ASM bytecode manipulation to add an Annotation to a foreign class, but it seems that I am missing something. The printed result is still without any annotation.

private void fixAnnotations4Classes() throws Exception {
        final ClassReader reader = new ClassReader("some/3rdparty/class/Foo");
        final ClassNode classNode = new ClassNode();
        reader.accept(classNode, 0);
        List<FieldNode> fields = classNode.fields;
        List<AnnotationNode> visibleAnnotations = fields.get(0).visibleAnnotations;
        visibleAnnotations.add(new AnnotationNode("my/new/Annotation"));

        ClassWriter writer = new ClassWriter(0);
        classNode.accept(writer);

        System.out.println(Arrays.toString(Foo.class.getDeclaredField("profile").getAnnotations()));
        System.out.println("FIN");
    }
KIC
  • 5,887
  • 7
  • 58
  • 98

2 Answers2

1

I was able to do this by calling visitAnnotation on a ClassVisitor. Values can then be set by calling visit on the resulting AnnotationVisitor. (This is assuming you already have a class visitor using whatever writing mechanism makes sense in the context.)

public class AnnotationAdjuster extends ClassVisitor {
    private static final ANNOTATION_TYPENAME="Lorg/acme/MyAnnotation;";

    @Override
    public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
       // This creates the annotation, but it will not have any parameters set on it
        AnnotationVisitor av = visitAnnotation(ANNOTATION_TYPENAME, true);
        Object value = "the-value-to-set";
    
        // This sets a parameter on the annotation
        // it could be called more than once for multiple parameters
        if (av != null) {
            av.visit("value", value);
        }
        super.visit(version, access, name, signature, superName, interfaces);
    }
}
Holly Cummins
  • 10,767
  • 3
  • 23
  • 25
0

While you are creating a new class with the additional annotation, you are never replacing the original class file that is actually loaded.

Your Foo class will therefore be loaded in its original version or it was already loaded such that your changes are a no-op.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192