Chapter 4. Capturing Joing Points on Methods

Introduction

A join point is a specific point at which advice can be woven into the code of an application. Pointcuts provide logical definitions for picking the join points that will invoke a piece of advice.

The next nine chapters correspond to the types of Java language constructs that contain join points that can be captured using pointcut declarations in AspectJ. This chapter focuses on pointcuts that can capture the selection of join points that are available on Java methods.

The before( ) form of advice is used for most of these pointcut-based recipes that make up the next eight chapters to avoid confusing things by using different types of advice. Where it’s unavoidable, other forms of advice may have to be used, so it might be helpful to refer to Chapter 9 to understand the implications that the different forms of advice bring to the solutions provided.

Tip

Once you have grasped the different types of pointcut that AspectJ provides in Chapter 4 through Chapter 12, check out Mik Kersten’s standard pointcut idioms by going to http://www.eclipse.org/aspectj and then by clicking on Documentation standard pointcut idioms. These reusable pointcut definitions provide some great tools with which to construct your own pointcut logic.

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

Warning

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.

How the call(Signature) pointcut is applied
Figure 4-1. How the call(Signature) pointcut is applied

Warning

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 http://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 http://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.

4.2. Capturing the Parameter Values Passed on a Method Call

Problem

You want to capture and use the parameters passed on a method call.

Solution

Create a pointcut that specifies the parameters that you want to capture as identifiers in its signature. Use the call(Signature) and args([TypePatterns | Identifiers]) pointcuts to capture the call to the method and then to bind the required identifiers to the values of the method’s parameters.

Discussion

Example 4-2 shows the call(Signature) pointcut being used to declare an interest in all methods that match the signature MyClass.foo(int,String). The captureCallParameters(int,String) pointcut requires an int and a String as specified by the value and name identifiers. Those identifiers are then bound to the methods parameters by the args([Types | Identifiers]) pointcut.

Example 4-2. Capturing the int and String values that are passed on a call to the MyClass.foo(..) method
public aspect CaptureCallParametersRecipe 
{
   /*
   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 captureCallParameters(int value, String name) : 
      call(void MyClass.foo(int, String)) && 
      args(value, name);

   // Advice declaration
   before(int value, String name) : captureCallParameters(value, name)
   {

      System.out.println(
         "------------------- Aspect Advice Logic --------------------");
      System.out.println(
         "In the advice attached to the call point cut");
      System.out.println("Captured int parameter on method: " + value);
      System.out.println("Captured String parameter on method: " + name);
      System.out.println(
         "------------------------------------------------------------");
   }
}

The before( ) advice can access the identifiers declared on the captureCallParame-ters(int,String) pointcut by including the value and name identifiers in its signature and then binding those identifiers to the captureCallParameters(int,String) pointcut.

See Also

The call(Signature) pointcut is described in Recipe 4.1; Recipe also Recipe 4.1 shows some of the wildcard variations that can be used in a Signature; Recipe 11.3 discusses the args([Types | Identifiers]) pointcut; combining pointcut logic using a logical AND (&&) is shown in Recipe 12.2; the before() form of advice is shown in Recipe 13.3; the calling context that is available to advice is covered in Chapter 13.

4.3. Capturing the Target of a Method Call

Problem

You want to capture the object being called as a method is invoked.

Solution

Create a pointcut that specifies a single parameter of the same type as the target of the method call that you want to capture. Use the call(Signature) and target(Type | Identifier) pointcuts to capture the invocation of a method and then to bind the single identifier to the object that the method is being called upon.

Discussion

Example 4-3 shows the call(Signature) pointcut being used to declare an interest in all methods that match the signature MyClass.foo(int,String). The captureCallTarget(MyClass) pointcut requires a MyClass object as specified by the myObject identifier. The myObject identifier is then bound to the object that is being called by the MyClass.foo(int,String) method by the target(Type | Identifier) pointcut.

Example 4-3. Capturing the object upon which the MyClass.foo(..) method is invoked
public aspect CaptureCallTargetRecipe 
{
   /*
   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 captureCallTarget(MyClass myObject) : 
      call(void MyClass.foo(int, String)) && 
      target(myObject);

   // Advice declaration
   before(MyClass myObject) : captureCallTarget(myObject)
   {

      System.out.println(
         "------------------- Aspect Advice Logic --------------------");
      System.out.println(
         "In the advice attached to the call point cut");
      System.out.println("Captured target object for the method call: " 
         + myObject);
      System.out.println(
         "------------------------------------------------------------");
   }
}

The before( ) advice can access the single identifier declared on the captureCallTar-get(MyClass) pointcut by including the myObject identifier in its signature and then binding that identifier to the captureCallTarget(MyClass) pointcut.

See Also

The call(Signature) pointcut is described in Recipe 4.1; Recipe 4.1 also shows some of the wildcard variations that can be used in a Signature; Recipe 11.2 discusses the target(Type | Identifier) pointcut; combining pointcut logic using a logical AND (&&) is shown in Recipe 12.2; the before( ) form of advice is shown in Recipe 13.3; the calling context that is available to advice is covered in Chapter 13.

4.4. Capturing a Method When It Is Executing

Problem

You want to capture when methods that match a specific signature are executing.

Solution

Use the execution(Signature) pointcut. The syntax of the execution(Signature) pointcut is:

pointcut <pointcut name>(<any values to be picked up>) : 
    execution((<optional modifier> <return type> <class>.<method>(<paramater types>);

Discussion

The execution(Signature) pointcut has two key characteristics:

  1. The context of a triggering join point is within the target class method.

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

Example 4-4 shows the execution(Signature) pointcut being used to declare an interest in method execution join points on any method that matches the signature MyClass.foo(int,String).

Example 4-4. Using the execution(Signature) pointcut to catch join points within the execution of a method
public aspect ExecutionRecipe 
{
   /*
       Specifies calling advice whenever a method 
       matching the following rules enters execution:
       
       Class Name: MyClass
       Method Name: foo
       Method Return Type: int
       Method Parameters: an int followed by a String
   */
   pointcut executionPointcut( ) : execution(void MyClass.foo(int, String));

   // Advice declaration
   before( ) : executionPointcut( ) && !within(ExecutionRecipe +)
   {
      System.out.println(
         "------------------- Aspect Advice Logic --------------------");
      System.out.println("In the advice picked by ExecutionRecipe");
      System.out.println(
         "Signature: "
            + thisJoinPoint.getStaticPart( ).getSignature( ));
      System.out.println(
         "Source Line: "
            + thisJoinPoint.getStaticPart( ).getSourceLocation( ));
      System.out.println(
         "------------------------------------------------------------");
   }
}

Figure 4-2 shows how the execution(Signature) pointcut is applied to a simple class.

How the execution(Signature) pointcut is applied
Figure 4-2. How the execution(Signature) pointcut is applied

At first, the execution(Signature) pointcut appears to offer nothing more than the call(Signature) pointcut described in the previous recipe. The important thing to remember with this recipe is where the advice is invoked and what is its context.

In the case of the call(Signature) pointcut, the advice is invoked where the method is invoked. The context of the advice invocation is the calling class. The execution(Signature) pointcut is invoked once the method has been entered and therefore the calling context is the method being executed.

Finally, if you haven’t already read Recipe 4.1, then it is worth going back a couple of pages to read about the strange behavior that the call(Signature) and execution(Signature) pointcuts can have when capturing join points on an object’s methods that are inherited and/or overridden depending on the object’s static and dynamic type.

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 http://www.cs.iastate.edu/~leavens/foal/papers-2004/barzilay-etal.pdf; Recipe 4.1 shows some of the wildcard variations that can be used in a Signature; how to capture parameters on a join point, in particular on a method call, is shown in Recipe 4.2; the calling context that is available to advice is covered in Chapter 13.

4.5. Capturing the Value of the this Reference When a Method Is Executing

Problem

When capturing a method during execution, you want to expose the object pointed to by the Java this reference so it can be used by your advice.

Solution

Create a pointcut that specifies a single parameter of the same type as the this reference you want to capture. Use the execution(Signature) and this(Type | Identifier) pointcuts to capture the execution of a method and then to bind the single identifier to the object that the this reference points to during the method’s execution.

Discussion

Example 4-5 shows the execution(Signature) pointcut being used to declare an interest in all methods that match the signature MyClass.foo(int,String). The captureThisDuringExecution(MyClass) pointcut requires a MyClass object as specified by the myObject identifier. The myObject identifier is then bound to the methods this reference by the this(Type | Identifier) pointcut.

Example 4-5. Capturing the this reference during the execution of the MyClass.foo(..) method
public aspect CaptureThisReferenceRecipe 
{
   /*
   Specifies calling advice whenever a method
   matching the following rules gets executed:
   
   Class Name: MyClass
   Method Name: foo
   Method Return Type: void
   Method Parameters: an int followed by a String
   */
   pointcut captureThisDuringExecution(MyClass myObject) : 
      execution(void MyClass.foo(int, String)) && 
      this(myObject);

   // Advice declaration
   before(MyClass myObject) : captureThisDuringExecution(myObject)
   {

      System.out.println(
         "------------------- Aspect Advice Logic --------------------");
      System.out.println(
         "In the advice attached to the execution point cut");
      System.out.println("Captured this reference: " + myObject);
      System.out.println(
         "------------------------------------------------------------");
   }
}

The before( ) advice can access the identifier that references the object originally pointed to by this during the method’s execution by including the myObject identifier in its signature and then binding that to the captureThisDuringExecution(MyClass) pointcut.

See Also

Recipe 4.1 shows some of the wildcard variations that can be used in a Signature; the execution(Signature) pointcut is shown in Recipe Recipe 4.4; how to capture parameters on a join point, in particular on a method call, is shown in Recipe 4.2; Recipe 11.1 discusses the this(Type | Identifier) pointcut; combining pointcut logic using a logical AND (&&) is shown in Recipe 12.2; the before( ) form of advice is shown in Recipe 13.3.

Get AspectJ Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.