I have a Java6 project that is being migrated to Java8. We used aspectj to log some of users actions, like button clicking.
So there are listeners like this:
button.addClickListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent clickEvent) {
doSth();
}
});
And poincut:
@Pointcut("execution(public void Button.ClickListener.buttonClick(Button.ClickEvent))")
public void buttonClick() {};
But since we will use Java8, listeners will be like this:
button.addClickListener(clickEvent -> doSth());
Is there any way to write aspectj pointcut, so that it handles new listeners?
I guess the problem is that lambdas do not seem to actually implement/override any interface methods with a corresponding name, but create an anonymous method. Look at this example:
Dummy button class, replicating the parts of Vaadin we need here:
Driver application:
As you can see, two button instances are created, one with a classical anonymous class listener, one with a lambda listener. Both buttons get clicked, so consequently the console log looks like this:
Aspect:
The first advice uses a pointcut similar to yours. It can only intercept classical listener declarations.
The second advice is for debugging purposes and logs all joinpoints within the driver application in order to show what the heck is going on here.
Last, but not least, the third advice shows a workaround for intercepting lambda-based listeners, relying on the knowledge about Java compiler naming for lambdas acquired from the debug output. This is not very nice, but for the moment it works. Please note that the lambda version of
buttonClick(..)
is not public, so it is justvoid *..lambda*
, notpublic void *..lambda*
.Console output with AspectJ:
Update: There is a corresponding Bugzilla issue now for AspectJ. I have just created it. It also points to a recent discussion on the mailing list.