java - 如果存在注释,则将接口(interface)添加到转换后的类

标签 java instrumentation java-bytecode-asm

我正在使用 asm 框架的 ClassAdapter 编写字节码转换器。如果类上存在自定义注释,我想添加一些方法并使类实现接口(interface)。添加方法工作正常,但我想知道让类实现接口(interface)的最佳方法是什么。由于 visitAnnotation 仅在 visit 之后调用,因此我需要以某种方式延迟调用 super 访问方法并缓冲所有需要的信息,直到那时。

有没有人实现过类似的东西?我是否应该为此使用 asm 的树 api,尽管包文档建议尽可能避免使用它?

这是转换的一般结构:

public class MyClassAdapter extends ClassAdapter {
    private String  classname;
    private boolean instrument;

    public PropertyChangeSupportAdapter(ClassVisitor cv) {
        super(cv);
    }

    @Override
    public void visit(final int version, final int access, final String name, final String signature, final String superName, final String[] interfaces) {
        super.visit(version, access, name, signature, superName, interfaces);
        this.classname = name;
    }

    @Override
    public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) {
        if (desc.equals("Lmypackage/MyAnnotation;")) {
            instrument = true;
            System.out.println("Instrumenting " + classname);
        }
        return super.visitAnnotation(desc, visible);
    }

    @Override
    public void visitEnd() {
        if (instrument) {
            // add methods
        }
    }
}

最佳答案

我最终使用了 ClassNode 和 ClassAdapter api 的组合。首先类文件被解析成一个ClassNode:

ClassReader cr = new ClassReader(inputStream);
ClassNode cn = new ClassNode();
cr.accept(cn, 0);

然后可以检查 cn.visibleAnnotation 或 cn.invisibleAnnotations 是否包含我的注释,以及该类是否已经实现了我要添加的接口(interface)。在这种情况下,可以跳过第二步。然后可以使用 ClassAdapter api 转换 ClassNode,如问题所示:

ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
CheckClassAdapter ca = new CheckClassAdapter(cw);
ClassVisitor cv = new PropertyChangeSupportAdapter(ca);
cn.accept(cv);

来自 package documentation 的注释,这就是我提出问题的原因,提到了这些 api 之间的巨大性能差异:

It is almost two times faster to read, "modify" and write a class with a ClassAdapter than with a ClassNode. ... This is also why it is recommended not to use this class adapter when it is possible.

再次重读之后,差异似乎来自于使用 ClassNode 来操作字节码。但是,我没有对这个混合解决方案进行基准测试。

关于java - 如果存在注释,则将接口(interface)添加到转换后的类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5413426/

相关文章:

java - Cucumber 中的 Rerun.txt 指的是类路径而不是 Feature 文件夹

java - try catch 异常(int 中的字母)

java - println如何打印一个对象

c++ - 自定义 "base"项目的事件检测 list 以满足 "derived"项目的需要

java - 调用通过 ByteBuddy 检测的 java 代理时出现异常

java - 如何使用反射以外的方式填充 JavaBean

java - 在 Java/Eclipse 中,为什么在我的代码中设置断点会改变该语句的效果?

python - 检测 Python 代码

java - 如何克服 JDK 7/8 应用程序的 "VerifyError:Expecting a stackmap frame"?

Java 字节码 - ASM - 获取标签偏移量