Aspectj Cookbook
Recipe 4.1. Capturing a Method Call
Problem
You want to capture when calls are made to methods that match a specific signature. Solution
Use the call(Signature) pointcut. The syntax of the call(Signature) pointcut is: pointcut <pointcut name>(<any values to be picked up>) : call(<optional modifier> <return type> <class>.<method>(<paramater types>));
Discussion
The call(Signature) pointcut has two key characteristics:
Table 4-1 shows some examples of the wildcard options available when using supplying a method Signature to a pointcut declaration.
Example 4-1 shows the call(Signature) pointcut being used to declare an interest in all methods that match the signature MyClass.foo(int,String). Example 4-1. Using the call(Signature) pointcut to catch calls to a specific method signature
public aspect CallRecipe { /* Specifies calling advice whenever a method matching the following rules gets called: Class Name: MyClass Method Name: foo Method Return Type: void Method Parameters: an int followed by a String */ pointcut callPointCut( ) : call(void MyClass.foo(int, String)); // Advice declaration before( ) : callPointCut( ) { System.out.println( "------------------- Aspect Advice Logic --------------------"); System.out.println( "In the advice attached to the call point cut"); System.out.println( "Actually executing before the point cut call ..."); System.out.println("But that's a recipe for Chapter 6!); System.out.println( "Signature: " + thisJoinPoint.getStaticPart( ).getSignature( )); System.out.println( "Source Line: " + thisJoinPoint.getStaticPart( ).getSourceLocation( )); System.out.println( "------------------------------------------------------------"); } }
Figure 4-1 shows how the call(Signature) pointcut is applied to a simple class. Figure 4-1. How the call(Signature) pointcut is applied
In AspectJ, the call(Signature) pointcuts and execution(Pointcuts) (see Recipe 4.4) can have strange behavior depending on the static and dynamic type of the target of the method. Consider the following: A someObject = new E( ); someObject.foo( );
In this simple example, E is a subclass of A; according to the dynamic typing rules in Java, the static type of someObject is A, whereas the dynamic type is E. You can then declare a call(Signature) pointcut to capture the call to someObject.foo( ): call(public void A.foo( ))
If the foo( ) method is declared in A and inherited by E, then the pointcut will capture the call to the method. However, if the foo( ) method is overridden in E, then the call(Signature) pointcut will still capture the method call join point. This may seem strange at first, but it makes sense if you think of the call(Signature) pointcut as examining the static type of someObject, which is still A. Now things get a little strange. What if you change the static type of someObject to E, leaving the foo( ) method being overridden in E, and change the code that uses the method to: E someObject = new E( ); someObject.foo( ); The static type of the object is the same as its dynamic type, both are E, which is still a subclass of A. foo( ) is overridden in E, then no code in A is invoked nor is the static type A referenced. Using the same pointcut definition as before you would not expect the call to someObject.foo( ) to be caught, but in fact it is. In this case you might have expected to be forced to use the + inheritance specifier to capture calls to foo( ), for example: call(public void A+.foo( )) // Captures calls to foo( ) on A and all subclasses Because of the way that the call(Signature) pointcut is implemented in AspectJ, you do not need the + specifier to capture calls to methods that are overridden in a subclass. It appears that even though the static and dynamic type of someObject is declared as E, because foo( ) is a method that exists on A, which is a still a super class of E, then the original call(Signature) pointcut definition still captures the method call. This appears even stranger when you consider the original pointcut definition does not even mention E nor does it use the + inheritance specification to indicate an interest in subclasses of A. This is just one example of the subtle and sometimes confusing ways the call(Signature) pointcut works with inherited and/or overridden methods depending on the static and dynamic types of an object and the type declared within the Signature. The execution(Signature) pointcut definition has similar but not identical problems because it puts more emphasis on the dynamic type of the object, which is what you'd perhaps expect when capturing join points that are within a method as opposed to on the call to a method. A complete investigation into these subtleties would require a full report, and one is available at www.cs.iastate.edu/~leavens/FOAL/papers-2004/barzilay-etal.pdf. Normal day-to-day use of the call(Signature) and execution(Signature) probably won't result in you encountering these issues; however it is helpful to at least keep them in mind and know of their existence just in case. See Also
The subtle characteristics of call(Signature) and execution(Signature) pointcuts when capturing join points in inherited or overridden methods are explained in more detail in the report available at www.cs.iastate.edu/~leavens/FOAL/papers-2004/barzilay-etal.pdf; how to capture parameters on a join point, in particular on a method call, is shown in Recipe 4.2; Chapter 13 describes the different types of advice available in AspectJ. |