I want to capture all method executions in com.ABC.MyClass using AspectJ
package com.ABC
public class MyClass{
public methodA(){
}
public methodB(){
methodA();
}
}
Below is the Aspect :
@Aspect
public class MyAspect{
@Pointcut("execution(* com.ABC.MyClass.*(..))")
public void captureMyClassMethods(){
}
@Around("captureMyClassMethods()")
public Object aroundMyClassMethods(ProceedingJoinPoint jp) throws Throwable{
MyClass object = (MyClass)jp.getTarget();
object.methodA(); //This causes infinite loop
Object o = jp.proceed();
System.out.println("Some data from o");
return o;
}
}
As mentioned in comments in around advice, while calling methodA() from advice is causing infinite loop.
As mentioned in another stackoverflow answer Aspectj - how to call advised method from within same advice, without triggering an infinite loop if I change the pointcut expression below then I would miss capturing execution of methodA() when it is called from methodB() because it will be in aspects control flow.
@Pointcut("execution(* com.ABC.MyClass.*(..)) && !cflow(within(MyAspect))")
Another way I can think of is using before and after advices instead of around advice. But I want to know if there is a way to handle this with around advice?
Actually, I am answering because your question presents a nice puzzle, not because I think that your use case is particularly relevant. Probably, it is rather a design flaw. I think, you should not try to call a method from an advice which is targeted by the same advice.
Both your variant
!cflow(within(MyAspect))and something like!adviceexecution()would, as you have noticed, preclude internal method calls from being captured.The workaround is an
if()pointcut and keeping state in a static, thread-local, boolean field, which is ugly and potentially slow. But if it works for you, you can do that.The
!staticqualifier avoids the staticmainmethod from beiong intercepted. There, the target object would benull, causing a null pointer exception when trying to call amethod upon it.Please also note how I am binding the target object to an advice parameter, which is more elegant than calling
jp.getTraget()and casting it.Last but not least, the
try-finallymakes sure to always reset the flag, even if there is an exception while callinghello.The console log looks like this:
As you can see, in this case the inner method calls inside
helloWorldare both captured correctly, but there is no stack overflow exception due to callinghellofrom the aspect