29

I have two different aspect classes to count the number of non-static method calls for an execution of a test program. The first aspect counts methods on "call" join points:

pointcut methodCalls() : call (!static * test..*(..));
before(): methodCalls() {
        counter.methodCallCounter();
}

while the second aspect counts methods on "execution" join points:

pointcut methodCalls() : execution (!static * test..*(..));
before(): methodCalls() {
        counter.methodCallCounter();
}

methodCallCounter() is a static method in counter class.

The number of method calls for small test program is the same. But when I change the test program with a larger program the number of method calls in the second aspect class (with execution pointcut) is more than the number of method calls in the aspect class with call pointcut. This is reasonable since the call join point does not pick out the calls made with super and therefore does not count them.

However, I encountered a case where for the specific execution of program the number non-static method calls in the aspect class with "call pointcut" was higher than the number of method calls in the aspect class with "execution pointcut". I can not find any interpretation why this is happening. Any thought about the reason of second situation is appreciated.

2
  • Not sure...I'd recommend printing out some information about the differences. Perhaps print out the 'thisJoinPoint' object. Commented Aug 8, 2013 at 19:16
  • 1
    There are a lot of differences between call() and execute(), read this blog: perfspy.blogspot.com/2013/09/…. Commented Sep 4, 2013 at 2:11

2 Answers 2

57

Actually, the explanation is quite simple if you understand the basic difference between call() and execution() pointcuts: While the former intercepts all callers (i.e. the sources of method calls), the latter intercepts the method executions themselves no matter where they originate from. In a nutshell: call affects the caller, execution the callee.

So how can the number of interceptions triggered by both pointcuts differ?

  • If you call JRE/JDK methods from your own code, AspectJ can weave into your calls, but not into the execution joinpoints within the JDK (unless you have created a woven JDK as a preparatory step). Thus, the number of calls will be higher than the number of executions.
  • Similarly, if you call methods in third party libraries which you have not woven with AspectJ because they were not on the in-path during LTW or CTW, again the executions will not be captured.
  • Last, but not least, it can happen the other way around if your own woven code is called by third party libs or by JRE/JDK classes. In this case the counted number of executions will be higher than the number of calls because they originate from places outside the control of your AspectJ code.

Generally, in all cases the reason is the difference between overall used code and the subset of woven code. In other words: the difference between code under and beyond your (or the aspects') control.

7
  • Can we just say that the call() is determined in compile-time while the execution() in runtime?
    – Hearen
    Commented Apr 12, 2018 at 2:12
  • 3
    No, we cannot. Pointcuts like cflow() or if () are determined at runtime.
    – kriegaex
    Commented Apr 12, 2018 at 3:59
  • @kriegaex how to make the choice between call() and execution() ? any resources?
    – Gaurav
    Commented Nov 13, 2018 at 11:36
  • 11
    The AspectJ manual explains the basic difference. In this answer I explain it a bit more verbose using pseudo code for better understanding. The basic difference is that call() weaves code into all places where a method is called, i.e. if it is called from 500 different places in your code, it weaves your advice code into those 500 places. However, execute() is woven into the method itself, i.e. only once, which is usually more efficient.
    – kriegaex
    Commented Nov 23, 2018 at 11:54
  • 3
    (continued) Which one to choose depends on whether you have control over the called code and can weave aspects into it. If you can, you will usually use execution(), if you cannot, you are left with call(). There might be other cases in which to choose call(), e.g. if you want to bind this() or use JoinPoint.getThis() in order to execute the calling object (caller) rather than the called object (callee). But this is too complex to explain in a short comment or two.
    – kriegaex
    Commented Nov 23, 2018 at 11:57
13

this image might help you visualize the difference between execution and call: call vs exe

Not the answer you're looking for? Browse other questions tagged or ask your own question.