Вчера вечером я играл с 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 для такой цели.
Спасибо за любые советы ;-) С наилучшими пожеланиями, Ксавье
Что вы на самом деле пытаетесь достичь здесь? Пока вы не объясните это, вам трудно посоветовать. –
«Извлеките лямбда-выражение», я понимаю, вы имеете в виду «сгенерировать». Кстати, сам вызов лямбда не является над InvokeDynamic, это используется только в процессе создания объекта лямбда-invocator. –
Я хотел бы захватить выражение Лямбда, которое было предоставлено в вызывающем коде, например, для целей ведения журнала или, например, для других способов использования. Я не говорю о создании байт-кода вместо JVM. Из приведенного выше примера, в методе 'filter (Filter)', я хотел бы вернуть данное выражение для выражения 'person -> person.getAge()> = minAge' лямбда выражение. Это выполнимо? –