Aspectj Cookbook

Recipe 6.2. Excluding Join Points That Are a Result of Advice Execution

Problem

You want to ignore all join points that are directly triggered within an advice block or as a result of advice execution. This is useful when you want to ignore anything an advice block triggered and just concentrate on join points that are within the control flow of your regular application's code business class's logic.

Solution

Supply the adviceexecution() pointcut declaration as the parameter to the cflow(Pointcut) pointcut. Use the unary NOT (!) operator to exclude the join points captured by the cflow(Pointcut) pointcut.

Discussion

It is sometimes useful to ignore the join points that occur directly within advice execution and those that may be triggered indirectly. If you use the within() pointcut with the unary NOT (!) operator alone, you can exclude all join points that occur directly within a particular aspect or aspects. However, any join points triggered indirectly by the advice within those aspects will still be caught.

An example of this problem can be demonstrated by amending the CallRecipe aspect from Recipe 4.1 as shown in Example 6-2. The before( ) advice has been enhanced to invoke the foo( ) method on the AnotherClass object.

Example 6-2. Making a call to the foo( ) method on the AnotherClass class from within some advice

public aspect CallRecipe { /* Specifies calling advice whenever a method matching the following rules gets called: Class Name: MyClass Method Name: foo Method Return Type: * (any return type) 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( "Signature: " + thisJoinPoint.getStaticPart( ).getSignature( )); System.out.println( "Source Line: " + thisJoinPoint.getStaticPart( ).getSourceLocation( )); AnotherClass anotherClass = new AnotherClass( ); anotherClass.foo( ); System.out.println( "------------------------------------------------------------"); } }

The foo( ) method on the AnotherClass object in turn makes a call to the bar( ) method on the same class:

public class AnotherClass { public void foo( ) { System.out.println("Inside method AnotherClass.foo( )"); this.bar( ); } public void bar( ) { System.out.println("Inside method AnotherClass.bar( )"); } }

Using the !within(CallRecipe+) pointcut as shown in Example 6-3, the call to foo( ) would be correctly excluded but the indirect call to bar( ) would still be captured by the tracedCalls( ) pointcut.

Example 6-3. Incorrectly protects an aspect from tracing using the within(TypePattern) pointcut and the Boolean NOT (!) operator

public aspect TraceCalls { /* Specifies calling advice when not within the TraceCalls and CallRecipe aspects or any of their subaspects. */ pointcut tracedCalls( ) : call(* *.*(..)) && !within(TraceCalls+) && !within(CallRecipe+); // Advice declaration before( ) : tracedCalls( ) { System.out.println( "------------------- Aspect Advice Logic --------------------"); System.out.println("In the advice picked by TraceCalls"); System.out.println( "Signature: " + thisJoinPoint.getStaticPart( ).getSignature( )); System.out.println( "Source Line: " + thisJoinPoint.getStaticPart( ).getSourceLocation( )); System.out.println( "------------------------------------------------------------"); } }

The call on the bar( ) method in the AnotherClass class is still caught by the before( ) advice because it does not occur directly in the CallRecipe aspect. However, it does occur within the control flow of the before( ) advice block in that the foo() method is called by the advice which, in turn, calls the bar( ) method.

The TRaceCalls( ) pointcut can be changed by adding a cflow(Pointcut) pointcut, combined with the adviceexecution( ) pointcut, so you can exclude even those join points that occur indirectly within the control flow of an advice block.

pointcut tracedCalls( ) : call(* *.*(..)) && !within(TraceCalls+) && !within(CallRecipe+) && !cflow(adviceexecution( ));

See Also

The call(Signature) pointcut is covered in Recipe Recipe 4.1; the cflow(Pointcut) pointcut is explained in Recipe Recipe 10.1; combining pointcut logic using a logical AND (&&) is shown in Recipe Recipe 12.2; the unary NOT (!) operator is shown in Recipe 12.4; Chapter 13 describes the different types of advice available in AspectJ.

Категории