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

Java 如何使用ASM框架访问匿名内部类,java,jvm,java-bytecode-asm,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类访问

例如,我需要在编译代码后访问run()中的信息

Class A{
    public static void main(String[] args){
        new Thread(new Runnable() {
            @Override
            public void run() {
                //something
            }
        }).start();
    }
}
我已经扩展了ASM类访问者,如何访问匿名内部类中的信息

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);
    }
}

您知道,像
Main$1
这样编译后的匿名内部类的名称。基于这一事实,我们可以通过override
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;
    }
}
公共类MyClassVisitor扩展ClassVisitor{
私有字符串ownerClassName;
公共MyClassVisitor(最终ClassVisitor简历){
超级(操作码ASM5,cv);
}
@凌驾
公共无效访问(int版本、int访问、字符串名称、字符串签名、,
字符串超名,字符串[]接口){
如果(cv!=null){
简历访问(版本、访问权限、姓名、签名、超名、接口);
ownerClassName=名称;
}
}
@凌驾
public方法访问者访问方法(int访问、字符串名称、字符串描述、,
字符串签名,字符串[]异常){
MethodVisitor mv=cv.visitMethod(访问、姓名、描述、签名、,
例外情况);
//编译后匿名内部类的名称如下:Main$1
字符串[]数组=ownerClassName.split($);
布尔值isNumber=false;
如果(array.length>1){
isNumber=array[array.length-1]。匹配(“[0-9]+”);
}
//如果它是一个匿名的内部类,并且该方法不是构造方法
if(isNumber&!name.equals(“”){
//返回自定义MethodVisitor以解析方法信息
返回新的MyMethodVisitor(mv);
}
返回mv;
}
}

您知道,像
Main$1
一样编译后的匿名内部类的名称。基于这一事实,我们可以通过override
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;
    }
}
公共类MyClassVisitor扩展ClassVisitor{
私有字符串ownerClassName;
公共MyClassVisitor(最终ClassVisitor简历){
超级(操作码ASM5,cv);
}
@凌驾
公共无效访问(int版本、int访问、字符串名称、字符串签名、,
字符串超名,字符串[]接口){
如果(cv!=null){
简历访问(版本、访问权限、姓名、签名、超名、接口);
ownerClassName=名称;
}
}
@凌驾
public方法访问者访问方法(int访问、字符串名称、字符串描述、,
字符串签名,字符串[]异常){
MethodVisitor mv=cv.visitMethod(访问、姓名、描述、签名、,
例外情况);
//编译后匿名内部类的名称如下:Main$1
字符串[]数组=ownerClassName.split($);
布尔值isNumber=false;
如果(array.length>1){
isNumber=array[array.length-1]。匹配(“[0-9]+”);
}
//如果它是一个匿名的内部类,并且该方法不是构造方法
if(isNumber&!name.equals(“”){
//返回自定义MethodVisitor以解析方法信息
返回新的MyMethodVisitor(mv);
}
返回mv;
}
}

匿名内部类的名称类似于MyClass$1。后缀在每个内部类中递增。我的意思是,如何使用ASM框架访问匿名内部类中的信息。谢谢可能提供一个简单的示例?我已经修改了问题并提供了示例。@Aimee Bordat方法
VisitInerClass
可能不是您想要的。它只提供您的姓名和访问信息。您需要覆盖
visitMethod
以访问方法信息。使用类名为
A$1
MyClassVisitor
。匿名内部类的名称为MyClass$1。后缀在每个内部类中递增。我的意思是,如何使用ASM框架访问匿名内部类中的信息。谢谢可能提供一个简单的示例?我已经修改了问题并提供了示例。@Aimee Bordat方法
VisitInerClass
可能不是您想要的。它只提供您的姓名和访问信息。您需要覆盖
visitMethod
以访问方法信息。使用
MyClassVisitor
类名称,如
A$1
。名称
Main$1
可以是类
Main
内的匿名内部类,也可以是方法
Main
内的匿名内部类,或者是具有显式名称
Main$1
的顶级类,您不知道。但这并不重要,因为您无论如何都没有检查
Main
。顺便说一句,不清楚为什么要对每个方法重复这个类名检查,而不是对整个类重复一次,即在
visit
方法中。如果你真的想知道这个类是否已经在一个方法中声明,你必须注意…@Holger:我已经意识到了这个问题,谢谢你的警告!名称
Main$1
可以是类
Main
内的匿名内部类,也可以是方法
Main
内的匿名内部类,或者是具有显式名称
Main$1
的顶级类,您不知道。但这并不重要,因为您无论如何都没有检查
Main
。顺便说一句,不清楚为什么要对每个方法重复这个类名检查,而不是对整个类重复一次,即在
visit
方法中。如果你真的想知道这个类是否已经在一个方法中声明,你必须注意…@Holger:我已经意识到了这个问题,谢谢你的警告!