Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I was playing with Java8 Lambda last night and I was wondering if it is possible to retrieve the Lambda expression at runtime. In short and as far as I understood, Lambda expression are converted into (static) methods at runtime and then called using InvokeDynamics.

Let's take an example like this:

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

where filter would be a custom method taking a Predicate<T>as a parameter. Inside this filter method, how could I retrieve the argument in a form similar (or identical) to the Lambda expression (person -> person.getAge() >= minAge) in this case ?

I tried to read the generated bytecode of the argument's class using ASM5_BETA but I couldn't go further than using a ClassVisitor and a MethodVisitor to reach the method associated with the Lambda expression.

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

I'm not sure this is the right path to follow, and I was wondering if there were more appropriate tooling in ASM or in JDK8 for such a purpose.

Thanks for any advice ;-) Best regards, Xavier

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
153 views
Welcome To Ask or Share your Answers For Others

1 Answer

You already know that lambda expressions are usually compiled into a synthetic method so you already know which code to decompile to get the lambda’s source code, or, well, something similar to the original code or even something looking completely different, depending on the particular code.

There is no reason why decompiling a lambda expressions should be easier than decompiling any other Java expression. Simple expressions might be easy to recover, especially when the code has debugging information, complex expressions are very likely to look different when decompiling, especially when the compiler applies optimizations to the code.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...