Ich spielte letzte Nacht mit Java8 Lambda und ich fragte mich, ob es möglich ist, den Lambda-Ausdruck zur Laufzeit abrufen. Kurz und soweit ich verstanden habe, werden Lambda-Ausdrücke zur Laufzeit in (statische) Methoden umgewandelt und dann mit InvokeDynamics aufgerufen.Ist es möglich, Lambda-Ausdruck zur Laufzeit abrufen
Nehmen wir ein Beispiel, wie diese nehmen:
people.filter(person -> person.getAge() >= minAge);
wo filter
eine benutzerdefinierte Methode eine Predicate<T>
als Parameter nehmen würde. Innerhalb dieser filter
Methode, wie konnte ich das Argument in einer Form ähnlich (oder identisch) mit dem Lambda-Ausdruck (person -> person.getAge() >= minAge
) in diesem Fall abrufen?
Ich versuchte, den generierten Bytecode der Klasse des Arguments mit ASM5_BETA zu lesen, aber ich konnte nicht weiter gehen, als mit einem ClassVisitor und einem MethodVisitor die Methode zu erreichen, die dem Lambda-Ausdruck zugeordnet ist.
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());
}
}
}
Ich bin nicht sicher, ob dies der richtige Weg ist, zu folgen, und ich frage mich, ob es in ASM oder in JDK8 für einen solchen Zweck geeignetere Werkzeuge waren.
Vielen Dank für jede Beratung ;-) Mit freundlichen Grüßen, Xavier
Was versuchen Sie eigentlich hier zu erreichen? Bis Sie das erklären, ist es schwierig, Sie zu beraten. –
Mit "Lambda-Ausdruck abrufen" nehme ich an, dass Sie "erzeugen" meinen. BTW der Lambda-Aufruf selbst ist nicht über InvokeDynamic, dies wird nur bei der Erstellung des Lambda Invocator-Objekts verwendet. –
Ich möchte den Lambda-Ausdruck erfassen, der im aufrufenden Code zur Verfügung gestellt wurde, zum Beispiel für den Zweck der Protokollierung oder andere Nutzungen später. Ich spreche nicht über die Generierung des Bytecodes anstelle der JVM. Aus dem obigen Beispiel möchte ich in der Methode filter (Filter) das gegebene Ausdruckargument in die Person -> person.getAge()> = minAge 'Lambda umwandeln können Ausdruck. Ist das machbar? –