Ich vermute das Problem ist, dass Lambdas nicht tatsächlich implementieren/überschreiben alle Schnittstellenmethoden mit einem entsprechenden Namen, sondern erstellen Sie eine anonyme Methode. Schauen Sie sich dieses Beispiel:
Dummy Schaltfläche Klasse, die Replikation, die Teile von Vaadin wir brauchen hier:
package de.scrum_master.app;
public class Button {
private ClickListener listener;
public void addClickListener(ClickListener listener) {
this.listener = listener;
}
public void click() {
System.out.println("Clicking button");
listener.buttonClick(new ClickEvent());
}
public static class ClickEvent {}
public static interface ClickListener {
public void buttonClick(ClickEvent clickEvent);
}
}
Treiber Anwendung:
package de.scrum_master.app;
public class Application {
protected static void doSomething() {}
public static void main(String[] args) {
Button button = new Button();
button.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent clickEvent) {
doSomething();
}
});
button.click();
button = new Button();
button.addClickListener(clickEvent -> doSomething());
button.click();
}
}
Wie Sie sehen können, mit zwei Tasten Instanzen werden erstellt, eine mit einem klassischen anonymen Klassen-Listener, eine mit einem Lambda-Listener. Beide Tasten geklickt erhalten, so damit das Konsolenprotokoll sieht wie folgt aus:
Clicking button
Clicking button
Richtung:
package de.scrum_master.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
@Aspect
public class ButtonClickLogger {
@Before("execution(public void *..Button.ClickListener.buttonClick(*..Button.ClickEvent))")
public void logButtonClick(JoinPoint thisJoinPoint) {
System.out.println("Caught button click: " + thisJoinPoint);
}
@Before("within(*..Application)")
public void logAllInListener(JoinPoint thisJoinPoint) {
System.out.println(" " + thisJoinPoint);
}
@Before("execution(void *..lambda*(*..Button.ClickEvent))")
public void logButtonClickLambda(JoinPoint thisJoinPoint) {
System.out.println("Caught button click (lambda): " + thisJoinPoint);
}
}
Die erste Beratung verwendet eine pointcut ähnlich wie bei Ihnen. Es kann nur klassische Listener-Deklarationen abfangen.
Der zweite Tipp ist für Debugging-Zwecke und protokolliert alle Joinpoints innerhalb der Treiber-Anwendung, um zu zeigen, was zum Teufel hier vorgeht. Der letzte Hinweis zeigt eine Problemumgehung zum Abfangen von lambda-basierten Listenern, wobei man sich auf das Wissen über die Java-Compiler-Benennung für Lambda verlässt, die von der Debug-Ausgabe erfasst wurden. Das ist nicht sehr nett, aber im Moment funktioniert es. Bitte beachten Sie, dass die Lambda-Version von buttonClick(..)
nicht öffentlich ist, so ist es nur void *..lambda*
, nicht public void *..lambda*
.
Konsolenausgabe mit AspectJ:
staticinitialization(de.scrum_master.app.Application.<clinit>)
execution(void de.scrum_master.app.Application.main(String[]))
call(de.scrum_master.app.Button())
call(de.scrum_master.app.Application.1())
staticinitialization(de.scrum_master.app.Application.1.<clinit>)
preinitialization(de.scrum_master.app.Application.1())
initialization(de.scrum_master.app.Application.1())
initialization(de.scrum_master.app.Button.ClickListener())
execution(de.scrum_master.app.Application.1())
call(void de.scrum_master.app.Button.addClickListener(Button.ClickListener))
call(void de.scrum_master.app.Button.click())
Clicking button
Caught button click: execution(void de.scrum_master.app.Application.1.buttonClick(Button.ClickEvent))
execution(void de.scrum_master.app.Application.1.buttonClick(Button.ClickEvent))
call(void de.scrum_master.app.Application.doSomething())
execution(void de.scrum_master.app.Application.doSomething())
call(de.scrum_master.app.Button())
call(void de.scrum_master.app.Button.addClickListener(Button.ClickListener))
call(void de.scrum_master.app.Button.click())
Clicking button
execution(void de.scrum_master.app.Application.lambda$0(Button.ClickEvent))
Caught button click (lambda): execution(void de.scrum_master.app.Application.lambda$0(Button.ClickEvent))
call(void de.scrum_master.app.Application.doSomething())
execution(void de.scrum_master.app.Application.doSomething())
Update: Es gibt einen entsprechenden Bugzilla issue jetzt AspectJ. Ich habe es gerade erstellt. Es verweist auch auf eine aktuelle Diskussion auf der Mailing-Liste.
Ich denke, Ihr 'pointcut' sollte immer noch funktionieren, weil Sie den' addClickListener' so geändert haben, dass 'Lambda' verwendet wird und Ihr' Button.ClickListener.buttonClick' immer noch den gleichen Namen hat. Hast du das auch geändert? –
Es funktioniert definitiv nicht. Ich habe AddClickListener nur geändert, um Lambda zu verwenden. Ja, es verwendet immer noch Button.ClickListener.buttonClick, aber die Funktion, die vor Pointcut ausgeführt werden soll (markiert als: @Before ("buttonClick()") wird nie aufgerufen. Es wird aufgerufen, wenn Nicht-Lambda-Definition verwendet wird. – Lete
Das bedeutet also dass AspectJ nicht in der Lage ist, die Methoden der durch die 'LambdaMetaFactory' erzeugten Listener-Klasse zur Laufzeit zu patchen. Kann es aber' default' Methoden von 'Schnittstellen' modifizieren? Das würde zu einer möglichen Lösung führen ... – Holger