如何使用ASM框架访问匿名内部类

时间:2017-03-14 07:04:55

标签: java jvm java-bytecode-asm

例如,我需要在编译代码后在run()中获取信息。

Class A{
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //something
            }
        }).start();
    }
}

我已经扩展了ASM ClassVisitor,我该如何访问匿名内部类中的信息。

public class MyClassVisitor extends ClassVisitor {

    public MyClassVisitor(final ClassVisitor cv) {
        super(Opcodes.ASM5, cv);
    }

    @Override
    public void visit(int version, int access, String name, String signature,
            String superName, String[] interfaces) {
        if (cv != null) {
            cv.visit(version, access, name, signature, superName, interfaces);
        }
    }

    @Override
    public void visitInnerClass(String name, String outerName, String innerName, int access) {
        //how should I do to access the information in an anonymous inner class
        super.visitInnerClass(name, outerName, innerName, access);
    }
}

1 个答案:

答案 0 :(得分:0)

您知道编译后的匿名内部类的名称,如Main$1。基于这一事实,我们可以通过覆盖visitMethod来访问方法信息。

代码如下。

public class MyClassVisitor extends ClassVisitor {

    private String ownerClassName;

    public MyClassVisitor(final ClassVisitor cv) {
        super(Opcodes.ASM5, cv);
    }

    @Override
    public void visit(int version, int access, String name, String signature,
            String superName, String[] interfaces) {
        if (cv != null) {
            cv.visit(version, access, name, signature, superName, interfaces);
            ownerClassName = name;
        }
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc,
            String signature, String[] exceptions) {
        MethodVisitor mv = cv.visitMethod(access, name, desc, signature,
                exceptions);
        //the name of anonymous inner class after compiled was like this: Main$1
        String[] array = ownerClassName.split("$");
        boolean isNumber = false;
        if(array.length > 1){
            isNumber = array[array.length - 1].matches("[0-9]+");
        }
        //if it's an anonymous inner class and the method was not construction method
        if(isNumber && !name.equals("<init>")){
            //return my custom MethodVisitor to parse the method information
            return new MyMethodVisitor(mv);
        }
        return mv;
    }
}