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
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:
Advice is triggered on a method call; the context is that of the calling class.
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.
Signature with wildcards |
Description |
|
Captures join points on a method regardless of the modifier. Can also be achieved by leaving out the visibility entirely. |
|
Captures join points on a method regardless of the modifier or return type. |
|
Captures join points on a method regardless of the modifier, return type, or class. |
|
Captures join points on a method regardless of the modifier, return type, class, or method. |
|
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. |
|
Captures join points on any method within the
|
|
Captures join points on any method on the |
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)
.
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.
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.
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.
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
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:
The context of a triggering join point is within the target class method.
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)
.
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.
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.
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.