The first three designators—execution, call, and initialization—are part of a set called the method-related pointcuts. You use these designators to match point- cuts when a method or constructor of a Java class is invoked and/or executed.
execution
The execution designator is matched by a join point defined on a method or constructor of a class within the primary application. Use this designator when you are interested in the actual execution of a method or constructor. The for- mat is
execution(join point signature)
Figure 6.1 shows where the match will occur using the execution designator.
Combining Pointcuts 87
public void doWork() { }
}
public static void main(String args) { Vector vec = new Vector(); vec.add(1);
myObj.doWork();
execution(public void doWork())
Joinpoint match
Joinpoint match code interruption
Figure 6.1 The execution designator.
You can write the join point signature using the full Java signature of a method/constructor or one of the many different combinations of wildcards shown in Chapter 5. Here’s an example of an execution pointcut:
pointcut Location() :
execution(public void setLocation(String));
This example defines a pointcut that cuts across all objects in the primary appli- cation that have a method called setLocation(String). The pointcut matches only when the method defined by the join point begins execution. In this case, we define execution as beginning at the moment just before the first statement in the method is to execute and ending after the last statement of the method/constructor.
The execution designator works on class constructors as well as methods. When you’re capturing a constructor join point, note that the only difference is the use of the new() pattern. For example:
This code will match the pointcut when the default constructor of any DVD object is executed. In either case—the method or the constructor signature— the execution designator will be matched when the application is executing within the scope of the signature’s object. At this point, the pointcut only knows about the called object and doesn’t know anything about the object or static method that made the originating method/constructor call. This is important because we will use another pointcut designator shortly that will allow us to obtain the context of the pointcut. Consider the pointcut defined earlier and some example advice:
pointcut DVDConstruct() : execution (public DVD.new(..)); before() : DVDConstruct() {
System.out.println(thisJoinPoint.toLongString()); }
The output from the previous pointcut using our DVD example code is
execution(public DVD(java.lang.String)) store 1
This output tells us that the AspectJ runtime system determined that a con- structor within the DVD class was being executed. When this determination was made, the pointcut advice code executed and displayed the full name of the matched join point.
Execution, Constructors, and Initializers
Consider the following short example:
public class Test {
public Vector vec = new Vector(); public Test() {
vec.add(1); }
public static void main(String[] args) { Test test = new Test();
} }
Here we find a class that creates a private vector and pushes an integer to it. Now consider this aspect:
public aspect TestVec {
pointcut vec(Test t) : execution(Test.new()) && this(t);
before(Test t) : vec(t) {
System.out.println("Size of Vector : " + vec.size()); } } AspectJ Pointcuts 88
TEAM
FLY
Team-Fly
®This aspect is designed to match the constructor of the Test class and execute advice before the constructor executes. The value output to the screen for the size of the vector in AspectJ version 1.0 is 1. However, in AspectJ 1.1, an excep- tion is thrown. This is because the initializer code—Vector vec = new Vector();—is considered part of the execution of the constructor and is not independent.
Because the initializer code is part of the constructor, we cannot work with any of the attributes or objects created because the constructor has not yet executed. This change between versions 1.0 and 1.1 doesn’t affect after advice because the constructor will have already executed before the after advice executes.
call
The call designator, shown in Figure 6.2, is also matched by a join point defined on a method or constructor. Use this designator when you are interested in the actual calling of a method or a constructor as opposed to the execution of code within a join point. The format of the designator is
call(join point signature)
Combining Pointcuts 89
public void doWork() { }
}
public static void main(String args) { Vector vec = new Vector(); vec.add(1);
myObj.doWork();
call(public void doWork())
Joinpoint match Joinpoint match code interruption
Figure 6.2 The call designator.
In Figure 6.2 we see that the call designator matches a join point before an exe- cution designator matches the same join point. Of particular importance is the context from which the match occurs. In the case of call, the context is the object making the call. In execution, control has passed to the target object of the method call:
call(join point signature)
Here’s an example of a call designator used in a pointcut:
pointcut DVDGetLoc() :
call(public String DVD.getLocation());
This pointcut tells us it will be matched when the getLocation() method of any DVD object is called. The scope of the pointcut remains with the object or sta- tic method that performed the actual call. Later in this chapter you learn how to
obtain both the caller of the method and the target object of the call. When the match occurs, the system hasn’t yet begun any execution of the method or con- structor; thus the match point indicates an intention to execute the named sig- nature. The pointcut can be combined with advice, as shown here:
pointcut DVDGetLoc() : call(public String DVD.getLocation()); before() : DVDGetLoc() {
System.out.println(thisJoinPoint.toLongString()); }
With the DVD example code and this pointcut, the following output is displayed to the console:
call(public java.lang.String DVD.getLocation()) store 1
The pointcut has been matched on the call to the getLocation() method. The output from the call designator doesn’t look that much different based on the use of the toLongString() context method. However, if we look ahead and use the this designator, we can see that we have full access to the object associated with the match join point. The following code uses the both the execution and call designators along with the this designator:
pointcut Stats(Object obj) :
execution(public void DVD.setStats(..)) && this(obj);
pointcut Stats2(Object obj);
call(public void DVD.setStats(..)) && this(obj);
pointcut allStats(Object obj) : Stats(obj) ||
Stats2(obj);
before(Object obj) : DVDGetLoc(obj) {
System.out.println(thisJoinPoint.toLongString()); if (obj instanceof DVD)
System.out.println("DVD object"); else if (obj instanceof Boxset)
System.out.println("Boxset object"); else
System.out.println("Unknown object"); }
When executed against the Boxset example code, the following output is produced:
call(public void DVD.setStats(java.lang.String, int)) Boxset object
execution(public void DVD.setStats(java.lang.String, int)) DVD object
AspectJ Pointcuts
As expected from the designator descriptions, the call designator matches on the call to the setStats() method from the Boxset object, whereas the execution designator matches the join point as it executes within the DVD object.
initialization
The initialization designator is used to match the constructor called when a new object is instantiated. The designator is designed so that all constructors in a hierarchy chain are called. The format of the initialization designator is
initialization (join point signature)
Here’s an example of the designator used in a pointcut:
pointcut Construct : initialization (new(..));
This pointcut creates a crosscut through the entire constructor chain of all objects in the system. In our example classes defined earlier in the chapter, the DVD class constructor calls the Product constructor through the use of the super() statement. The pointcut is matched when the DVD constructor is called and when the Product constructor is called. The order of the join points are the Product and then the DVD constructor because the Product constructor is actu- ally the first constructor to execute. This is because the super() statement has a special meaning in the Java language.
The output from our example classes would be different if we changed the join point signature to something along the lines of
pointcut DVDconstruct : initialization (DVD.new(..));
This pointcut includes a join point that narrows the scope of the crosscut to only the DVD class. The join point for the Product constructor is not recog- nized. In another example, consider several classes that implement and extend each other:
interface NewInterface {} class Inner1 {}
class Inner2 extends Inner1 {}
class Outer extends Inner2 implements NewInterface { public static void main(String[] args) {
Outer outer = new Outer(); }
This initialization designator would match the Outer class:
pointcut outerMatch() : initialization(Outer.new());
If executed, the matches made by the pointcut would be as follows:
Inner1 Inner2 NewInterface Outer
The initialization designator matches all the constructors found in the entire hierarchy of the instantiated object. In our example, the Outer class extends the Inner2 class, which itself extends Inner1. The execution of the code requires that the Inner1 constructor be called first because it is the foundation of all the other classes.