Is it possible to retrieve a lambda expression at runtime

I played with Java8 Lambda yesterday, and I was wondering if it is possible to get a Lambda expression at runtime. In short, as I understand it, a Lambda expression is converted to (static) methods at runtime, and then called using InvokeDynamics.

Take this example:

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

where filter will be the usual method taking Predicate<T> as a parameter. Inside this filter method, how could I get an 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 class using ASM5_BETA, but I couldn't go further than using ClassVisitor and MethodVisitor to get 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 if this is the right way, and I wondered if the ASM or JDK8 had more suitable equipment for this purpose.

Thanks for any advice ;-) Best regards, Xavier

+5
source share
2 answers

You already know that lambda expressions are usually compiled into a synthetic method, so you already know what code you need to decompile to get the lambdas source code, or something similar to the source code or even something completely different, depending from a specific code.

There is no reason why decompiling lambda expressions should be simpler than decompiling any other Java expression. Simple expressions can be easily restored, especially when the code has debugging information. Complex expressions are more likely to look different when decompiling, especially when the compiler applies optimization to the code.

+4
source

You can do this in some cases with Groovy if this helps you: Retrieve closure content in groovy . Geb actually uses this function to highlight the statement error inside the evaluated expression.

0
source

Source: https://habr.com/ru/post/969412/


All Articles