是否可以在运行时检索lambda表达式

时间:2013-12-17 08:15:12

标签: java lambda bytecode java-8

昨晚我正在玩Java8 Lambda,我想知道是否可以在运行时检索Lambda表达式。简而言之,据我所知,Lambda表达式在运行时转换为(静态)方法,然后使用InvokeDynamics进行调用。

我们举个这样的例子:

people.filter(person -> person.getAge() >= minAge);

其中filter是一个以Predicate<T>为参数的自定义方法。 在这个filter方法中,如何在这种情况下以与Lambda表达式(person -> person.getAge() >= minAge)相似(或相同)的形式检索参数?

我尝试使用ASM5_BETA读取参数类的生成字节码,但我无法使用ClassVisitor和MethodVisitor来访问与Lambda表达式相关联的方法。

public <T> List<T> filter(Filter<T> expression) {
    try {
        Class<? extends Filter> expressionClass = expression.getClass();
        byte[] content = getClassContent(expressionClass);
        ClassReader classReader = new ClassReader(content);
        classReader.accept(new PredicateClassVisitor(), 0);
    } catch (Throwable e) {
        e.printStackTrace();
    }
    return null;
}

private byte[] getClassContent(Class<? extends Filter> expressionClazz) throws  
               IOException {
    InputStream stream = Thread.currentThread().getContextClassLoader()
                           .getResourceAsStream(getClassName(expressionClazz.getName()));
    return IOUtils.toByteArray(stream);
}

private String getClassName(String expressionClazz) {
    return expressionClazz.substring(0, expressionClazz.indexOf('$'))
           .replace('.', '/') + ".class";
}

static class PredicateClassVisitor extends ClassVisitor {

    public PredicateClassVisitor() {
        super(Opcodes.ASM4);
    }

    @Override
    public MethodVisitor visitMethod(int i, String s, String s2, String s3, 
                                     String[] strings) {
        return new PredicateMethodVisitor();
    }
}

static class PredicateMethodVisitor extends MethodVisitor {

    public PredicateMethodVisitor() {
        super(Opcodes.ASM4);
    }

    @Override
    public void visitInvokeDynamicInsn(String name, String desc, Handle bsm,
                                       Object... bsmArgs) {
        for (Object object : bsmArgs) {
              System.out.println(" " + object.toString());
        }
    }
} 

我不确定这是正确的路径,我想知道ASM或JDK8中是否有更合适的工具用于此目的。

感谢您的任何建议;-) 最好的祝福, 泽维尔

2 个答案:

答案 0 :(得分:4)

你已经知道lambda表达式通常被编译成一个合成方法,所以你已经知道要反编译哪些代码来获取lambda的源代码,或者,类似于原始代码的东西,甚至看起来完全不同的东西,取决于特定的代码。

没有理由反编译lambda表达式比反编译任何其他Java表达式更容易。简单表达式可能很容易恢复,特别是当代码具有调试信息时,复杂表达式在反编译时很可能看起来不同,特别是当编译器对代码应用优化时。

答案 1 :(得分:1)

在某些情况下,您可以使用Groovy执行此操作,如果这可以帮助您:Getting the contents of closure, in groovyGeb实际上使用此功能突出显示评估表达式中的断言错误。