CFlow, or control flow, allows the selection of pointcuts based on the program flow at runtime. Most of the pointcuts you’ve reviewed so far have probably been selectable at weave time. For example, call matches pointcuts that call a particular method; execution matches the execution of code whose signature matches. AspectJ determines both of these examples without having to execute the program.
What about wanting to capture a pointcut so long as it is not called while in another method? In our example, we want to disable change tracking if changes occur either directly in a constructor or are called as a result of a (below in the stack trace) of a constructor. For example:
The pointcut “set(* Address.name)” matches lines 2 and 8. In this code example, we have the following sequences that cause the pointcut to be encountered at runtime:
So in the dynamic execution of this program, we encounter a pointcut matching set(* Address.name) a total of 5 times (these are labeled a through e in the example). Of these 5 paths to the pointcut, which ones cause change tracking to occur? In our example, we ignore “cflow(execution(cf.ITrackedObject+.new (..)))” - or all constructors under the ITrackedObject interface.
So any of the above lines that pass through the constructor in Address will be ruled out. That includes: a, b and c. The other two, d and e, get to the same pointcuts. However, they do not pass through the constructor, so they are not excluded by the cflow expression.
What follows is a breakdown of all the code for this example.
Address.java
Interesting Lines
Line
Description
14
This line causes a field to be set. If we did not do this, then we would not see any changes to the address object at construction time and this cflow example would have no motivation.
We define a pointcut called constructors. Working right to left, we have: cf.ITrackedObject+.new (..), which means constructors (new) taking any parameters (..) off of the class cf.ITrackedObject+, or any class that implements ITrackedObject. We introduce this class to Address via another Aspect (see {: #InnerTypeAspect}). Next, we have: (execution(cf.ITrackedObject+.new (..))), which means the execution of this method. So we are modifying the bytecode associated with the constructor, not the call of the constructor. Finally, we put that whole thing in cflow(…). This says any pointcuts that we hit from the execution of all constructors in any class that implements ITrackedObject. If we wanted to keep the pointcuts in the constructor but capture anything below that, we could have used cflowbelow.
25
This is where we actually use the constructors pointcut. Notice we negate it using !. This means that the following Around advice, called trackFieldAssignment, will not execute if we happen to hit any of the constructor pointcuts. Since the around advice does not apply to constructors, any changes that happen there or below will NOT cause change tracking to occur.
We construct an address. In [[AspectJ_Example_4] this did not cause a change because construction did not cause anything to be initialized. In this exercise we found out that if it had, it would cause Address to be changed. We managed to change that by using cflow.
Comments