Recipe4.1.Capturing a Method Call


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>));

In contrast to Java method parameters, whitespace in the Signature parameter is important as it is used to separate out the different components.


Discussion

The call(Signature) pointcut has two key characteristics:

  1. Advice is triggered on a method call; the context is that of the calling class.

  2. The Signature can include wildcard characters to select a range of join points on different classes and methods.

Table 4-1 shows some examples of the wildcard options available when using supplying a method Signature to a pointcut declaration.

Table 4-1. Examples of using wildcards within a method Signature

Signature with wildcards

Description

* void MyClass.foo(int, float)void MyClass.foo(int, float)

Captures join points on a method regardless of the modifier. Can also be achieved by leaving out the visibility entirely.

* * MyClass.foo(int, float)* MyClass.foo(int, float)

Captures join points on a method regardless of the modifier or return type.

* * *.foo(int,float)* * foo(int,float)

Captures join points on a method regardless of the modifier, return type, or class.

* * *.*(int,float)

Captures join points on a method regardless of the modifier, return type, class, or method.

* * *.*(*,float)

Captures join points on a method regardless of the modifier, return type, class, or method where the parameters include anything followed by a float.

* * *.*(*,..)

Captures join points on a method regardless of the modifier, return type, class, or method where the parameters include at least a single value followed by any number of parameters.

* * *.*(..)* *(..)

Captures join points on a method regardless of the modifier, return type, class, or method where there are any number of parameters.

* mypackage..*.*(..)

Captures join points on any method within the mypackage package and subpackages.

* MyClass+.*(..)

Captures join points on any method on the MyClass class and any subclasses.


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


Be aware that the call(Signature) and execution(Signature) pointcut definitions can result in strange behavior in certain situations when capturing join points on an object's inherited and/or overridden methods, depending on the dynamic and static types of the object.


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.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net