2015-11-25 7 views
5

Ich versuche Anrufe Methoden abfangen und ruft Java 8 Lambda-Ausdrücke mit einem Byte Buddy AgentBuilder wie folgt:Intercepting Anrufe auf Java 8 Lambda-Ausdrücke Byte Buddy

static { 
    final Instrumentation inst = ByteBuddyAgent.install(); 
    new AgentBuilder.Default() 
     .type(ElementMatchers.nameContainsIgnoreCase("foo")) 
     .transform((builder, typeDescription) -> 
       builder.method(ElementMatchers.any()) 
         .intercept(MethodDelegation.to(LogInterceptor.class))) 
     .installOn(inst); 
} 

public static class LogInterceptor { 
    @RuntimeType 
    public static Object log(@SuperCall Callable<?> superCall) throws Exception { 
    System.out.println("yeah..."); 
    return superCall.call(); 
    } 
} 

Ich verwende Byte Buddy v0 .7.1.

Es kann die folgenden Runnable (anonyme Klasse) abfangen:

FunnyFramework.callMeLater(new Runnable() { 
    @Override 
    public void run() { 
     System.out.println("Hello from inner class"); 
    } 
}); 

und natürlich alle Anrufe auf Objekte definiert als normalen (nicht anonym) Klassen. Aber das Abhören funktioniert nicht für die Lambda-Ausdruck ist wie:

FunnyFramework.callMeLater(() -> { 
    System.out.println("Hello from lambda"); 
}); 

Wie kann ich Expression Anrufe auch die Lambda abfangen? Es gibt kein LambdaInterceptor in Byte Buddy, soweit ich weiß.

+2

Das Instrumentieren von Lambda-Ausdrücken ist jetzt ab Byte Buddy 1.1.0 möglich –

Antwort

7

Die Java Virtual Machine lässt keine Umwandlung einer Klassendatei zu, die einen Lambda-Ausdruck darstellt. Klassen, die Lambda-Ausdrücke darstellen, werden durch sogenannte anonymous class loaders (nicht zu verwechseln mit klassischen anonymous classes), die den Sicherheitskontext einer anderen Klasse erben, z. Eine Klasse, die mit einem anonymen Klassenlader geladen wird, der die geladene Klasse an eine andere Klasse Foo bindet, kann auf private Methoden von Foo zugreifen. Dieses Laden geschieht explizit mit der sun.misc.Unsafe API.

Byte Buddy Haken in die Java instrumentation API, die die Anwendung von ClassFileTransformer s in einen ClassLoader s Ladevorgang einhängen ermöglicht. Da anonyme Klassenlader nicht als ClassLoader s im üblichen Sinne betrachtet werden, erlaubt die Instrumentierungs-API solche Instrumentierungen nicht und verbietet daher die Instrumentierung von Lambda-Ausdrücken.

Dies ist natürlich unglücklich für einige Anwendungsfälle, aber in den meisten realen Anwendungen gibt es keine wirkliche Anforderung für die Instrumentierung der Lambda-Expression. Viele reale Instrumentierungen werden beispielsweise auf Methoden angewendet, die mit einer bestimmten Annotation versehen sind, was nicht auf Lambda-Ausdrücke oder auf Klassen angewendet werden kann, die komplexer sind als eine funktionale Schnittstelle.


UPDATE: Mit Byte Buddy Version 1.1.0 ist es zu Geräteklassen möglich, die Lambda-Ausdrücke darstellen. Byte Buddy instrumentiert hierzu die JVM LambdaMetafactory und ersetzt die Klassengeneration durch eine benutzerdefinierte Definition. Um diese Funktion zu aktivieren, den folgenden Schritt im Builder ausführen:

new AgentBuilder.Default() 
    .with(LambdaInstrumentationStrategy.ENABLED) 

Beachten Sie, dass dies nur mit OpenJDK 8u40 funktioniert, die in früheren Versionen, gibt es einen Fehler zu invokedynamic Aufrufstellen im Zusammenhang, dass diese von der Arbeit verhindert.

Verwandte Themen