Вчера вечером я играл с Java8 Lambda, и мне было интересно, можно ли получить выражение Lambda во время выполнения. Короче говоря, насколько я понял, лямбда-выражения преобразуются в (статические) методы во время выполнения, а затем вызываются с помощью InvokeDynamics.
Возьмем такой пример:
people.filter(person -> person.getAge() >= minAge);
где filter
будет настраиваемым методом, принимающим Predicate<T>
в качестве параметра. Как в этом методе filter
получить аргумент в форме, аналогичной (или идентичной) лямбда-выражению (person -> person.getAge() >= minAge
) в этом случае?
Я попытался прочитать сгенерированный байт-код класса аргумента, используя ASM5_BETA, но не смог пойти дальше, чем использовать ClassVisitor и MethodVisitor, чтобы добраться до метода, связанного с лямбда-выражением.
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 для такой цели.
Спасибо за любой совет ;-) С уважением, Ксавьер
filter(Filter<T> expression)
я хотел бы иметь возможность вернуть данныйexpression
argument кperson -> person.getAge() >= minAge
лямбда-выражению. Это выполнимо? - person Xavier Coulon   schedule 17.12.2013