Recipe11.3.Capturing When the Arguments to a Join Point Are a Certain Number, Type, and Ordering


Recipe 11.3. Capturing When the Arguments to a Join Point Are a Certain Number, Type, and Ordering

Problem

You want to capture all join points encountered when a join point's arguments, if any, are of a specific type, number, and ordering.

Solution

Use the args([Types | Identifiers]) pointcut. The syntax for this pointcut is:

pointcut <pointcut name>(<any values to be picked up>) :              args(<types> or <identifiers> | .. | *, <repeat>);

Discussion

The args([Types | Identifiers]) pointcut has seven key characteristics:

  1. Any combination of Types and Identifiers can be used to narrow to the right join points and expose the right context to the advice.

  2. An Identifier is used to examine the type of the runtime objects that are the arguments at the captured join point and to expose those objects to the advice if required.

  3. Using .. allows you some flexibility in the number of arguments that a particular join point must have to match against your args([Types | Identifiers]) declaration.

  4. Without the .., the args([Types | Identifiers]) pointcut picks all join points that exactly match the types of the arguments specified. This is to say that the pointcut will only match join points on methods that have the same order, number, and types of parameters at runtime.

    With the .., a "best fit" policy is used by the pointcut. This means the statement args(MyClass,..,float) would result in any join points being matched that have two arguments, starting with a MyClass object and followed by any number of arguments that include a float amongst them.

  5. Only one .. can be used in a single args([Types | Identifiers]) declaration.

  6. Using a * wildcard allows you to express some flexibility in the type of an argument, but the number of arguments to a join point must match up.

    For example, if a single * is specified within an args([Types | Identifiers]) pointcut declaratione.g., args(*)then this pointcut would match any join point that had one argument of any type and ignore any join points that had no arguments. Similarly, the statement args(*,*) would match any join point that contained two arguments of any type.

  7. Join points that occur on a field access, caught by either the get(TypePattern) and set(TypePattern) pointcuts, or static class initialization, caught by the staticinitialization(TypePattern) pointcut, do not have any arguments to expose using the args([Types | Identifiers]) pointcut.

  8. If Object is used as the type for an identifier to be picked up by the args([Types | Identifiers]) pointcut, then this will successfully match against primitive types as well as specific instances of Object. The primitive type is automatically "boxed" into its corresponding object type, Float in the case of a float primitive for example, before being passed to the advice. This behavior provides a means by which you can get primitive argument values into your advice.

Example 11-3 shows two examples of the args([Types | Identifiers]) pointcut being used to:

  • Capture all join points where the arguments to the methods are an object of the MyClass class as indicated by Identifier

  • Capture join points where the type of the argument is that of the AnotherClass class as specified by Type

Example 11-3. Using the args([Types | Identifiers]) pointcut to capture join points based on the types of a methods arguments
public aspect ArgsRecipe  {    /*        Specifies calling advice whenever the type of a methods argument         is of a type that matches the following rules:            Identifier/s: MyClass object    */    pointcut argIdentifierMyClassPointcut(MyClass object) : args(object);    /*        Specifies calling advice whenever the type of a methods argument         is of a type that matches the following rules:                Type Pattern: AnotherClass    */    pointcut argTypePatternAnotherClassPointcut( ) : args(AnotherClass);    // Advice declaration    before(MyClass object) : argIdentifierMyClassPointcut(object)       && !within(ArgsRecipe +)    {       System.out.println(          "------------------- Aspect Advice Logic --------------------");       System.out.println(          "In the advice picked by argIdentifierMyClassPointcut");       System.out.println("Join Point Kind: " + thisJoinPoint.getKind( ));       System.out.println(          "Signature: " + thisJoinPoint.getStaticPart( ).getSignature( ));       System.out.println(          "Source Line: " + thisJoinPoint.getStaticPart( ).          getSourceLocation( ));       System.out.println(             "Arguments picked up using Identifiers: " + object);       System.out.println(          "------------------------------------------------------------");    }    // Advice declaration    before( ) : argTypePatternAnotherClassPointcut( ) && !within(ArgsRecipe +)    {       System.out.println(          "------------------- Aspect Advice Logic --------------------");       System.out.println(          "In the advice picked by argTypePatternAnotherClassPointcut");       System.out.println("Join Point Kind: " + thisJoinPoint.getKind( ));       System.out.println(          "Signature: " + thisJoinPoint.getStaticPart( ).getSignature( ));       System.out.println(          "Source Line: " + thisJoinPoint.getStaticPart( ).          getSourceLocation( ));       System.out.println(          "------------------------------------------------------------");    } }

Figure 11-3 shows how the args([Types | Identifiers]) pointcut is applied.

Figure 11-3. How the args(Types | Identifiers) pointcut is applied


Problems can occur with method overloading if you overload by creating a new method with fewer parameters than the original method. The args([Types | Identifiers]) pointcut examines the number, types, and order of the arguments at a join point, and so an overloaded method that provides fewer parameters may not trigger advice that was triggered by the original method.


See Also

Recipes Recipe 11.1 and Recipe 11.2 describe the this([Type | Identifier]) and target([Type | Identifier]) pointcuts respectively; the get(TypePattern) and set(TypePattern) pointcuts are described in Recipes Recipe 8.1 and Recipe 8.3 respectively; the calling context that is available to advice is covered in Chapter 13; the within(TypePattern) pointcut is described in Recipe 9.1; the NOT(!) operator is described in Recipe 12.4.



AspectJ Cookbook
Aspectj Cookbook
ISBN: 0596006543
EAN: 2147483647
Year: 2006
Pages: 203
Authors: Russ Miles

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net