Join point selection pattern language

AspectWerkz support a fine-grained pattern language for picking out join points.

You can utilize two types of wildcards when constructing your patterns:

  • * - which is used as a regular wildcard. Matches for example only one package level or one method parameter. When used to match a package name, matches at least one character. Else match zero or more character.


  • .. - matches any sequence of characters that start and end with a ".", so it can be used to pick out all types in any subpackage. For example org.codehaus..* will match all classes in all subpackages starting from org.codehaus.
Note: you can only use the .. wildcard as the "last" thing specified. I.e. this is not possible: foo.bar..test.MyClass, but this is: foo.bar... The same thing holds for method parameters.

Combining the patterns

The patterns normally consists of a combination of a class and a method pattern or a class and a field pattern.

Example of a full method pattern:

<annotations> <modifiers> <return_type_pattern> <package_and_class_pattern>.<method_name_pattern>(<parameter_type_patterns>)

Example of a full field pattern:

<annotations> <modifiers> <field_type_pattern> <package_and_class_pattern>.<field_name_pattern>

Class selections

The classes are selected by specifying a pattern that consists of:

  • the annotations
  • the modifiers
  • the full name of the class

All class patterns must follow this structure:

<annotations> <modifiers> <full_class_name>

For the class selections specify the full package name of the class along with some wildcards.

Examples:

  • foo.bar.* - will match

    foo.bar.FooBar2 as well as

    foo.bar.FooBear but not

    foo.bar.subpackage.FooMouse


  • foo.*.FooBar - will match

    foo.bar.FooBar as well as

    foo.bear.FooBar but not

    foo.bear.FooBear.


  • foo.*.FooB* - will match

    foo.bar.FooBar2 as well as

    foo.bear.FooBear as well as

    foo.bear.FooB.


  • public foo.bar.* - will match

    public static final foo.bar.FooBar as well as

    public static foo.bar.FooBar but not

    static foo.bar.FooBar or

    private foo.bar.FooBar.


  • @Session foo.bar.* - will match

    @Session foo.bar.FooBar but not

    foo.bar.FooBar or

    private foo.bar.FooBar.


  • foo.. - will match

    all classes in all packages starting with foo.

Method selections

The methods are selected by specifying a pattern that consists of:

  • the annotations
  • the modifiers
  • the return type
  • the full name of the method (including class and package)
  • the parameter types

All method patterns must follow this structure:

<annotations> <modifiers> <return_type> <full_method_name>(<parameter_types>)

Examples

  • int foo.*.Bar.method() - will match

    int method() but not

    int method(int i).


  • int *.method(*) - will match

    int Foo.method(int i) but not

    int Foo.method() and not

    int apackage.Foo.method(int i)


  • * method(..) - will match

    void Foo.method() as well as

    void apackage.Bar.method(int[] i)


  • int foo.*.*.method(*,int) - will match

    int method(String s, int i) as well as

    int method(int i1, int i2).


  • int foo.*.Bar.method(..) - will match

    int method() as well as

    int method(String s, int i) as well as

    int method(int i, double d, String s, Object o).


  • int foo.*.Bar.method(int,..) - will match

    int method(int) as well as

    int method(int i, String s) as well as

    int method(int i, double d, String s, Object o).


  • int foo.*.Bar.method(java.lang.*) - will match

    int method(String s) as well as

    int method(StringBuffer sb).


  • int foo.*.Bar.me*o*() - will match

    int method() as well as

    int metamorphosis() and int meo() but not

    int me().


  • * foo.*.Bar.method() - will match

    int method() as well as

    java.lang.String method().


  • java.lang.* foo.*.Bar.method() - will match

    java.lang.String Bar.method() as well as

    java.lang.StringBuffer Bar.method().


  • static int foo.*.Bar.method() - will match

    static int method() but not

    int method(int i).


  • @Transaction * foo.*.*.*(..) - will match

    @Transaction int method() but not

    void method(int i).

Constructor selections

The constructors are selected by specifying a pattern that consists of:

  • the annotations
  • the modifiers
  • the fully qualified name of the class (including package) plus the word 'new' as constructor name
  • the parameter types

All the patterns must follow this structure:

<annotations> <modifiers> <className>.<new>(<parameter_types>)

Examples

  • foo.*.Bar.new() - will match

    new Bar() but not

    new Bar(int i).


  • * new(..) - will match

    new Foo() as well as

    new apackage.Bar(int[] i)


  • *.new(String) - will match

    new Foo(String name) and

    new Bar(String name) but not

    new Foo().


Field selections

The fields are selected by specifying a pattern that consists of:

  • the annotations
  • the modifiers
  • the field type
  • the full name of the field (including class and package)

All field patterns must follow this structure:

<annotations> <modifiers> <field_type> <full_field_name>

Examples

  • int foo.*.Bar.m_foo - will match

    int m_foo but not

    int s_foo or

    long m_foo.


  • * m_field - will match

    int Foo.m_field as well as

    int[] apackage.Bar.m_field


  • * foo.*.Bar.m_foo - will match

    int m_foo as well as

    java.lang.String m_foo.


  • java.lang.* foo.*.Bar.m_foo - will match

    java.lang.String m_foo as well as

    java.lang.StringBuffer m_foo.


  • int foo.*.Bar.m_* - will match

    int m_foo as well as

    int m_bar.


  • int foo.*.Bar.m_*oo* - will match

    int m_foo as well as

    int m_looser as well as

    int m_oo.

Subtype patterns

It is possible to pick out all subtypes of a type with the "+" wildcard. The "+" wildcard follows immediately a type name pattern. So, while

* foo.Bar.*(..)

picks out all method call join points where an instance of exactly type Foo is constructed,

* foo.Bar+.*(..)

picks out all method call join points where an instance of any subtype of Foo (including Foo itself) is constructed.

Array type patterns

A type name pattern or subtype pattern can be followed by one or more sets of square brackets to make array type patterns. So Object[] is an array type pattern, and so is foo.bar.*[][].

Abbreviations

When picking out the return and parameter types it is possible to use predefined abbreviations for the classes in the java.lang.* and java.util.* packages. If you specify only the class name it will be mapped to the full class name for the class (you cannot use patterns in abbreviations).

Abbreviations are supported for array types as well, with a dimension less or equal to 2. String[][] will thus be resolved as java.lang.String[][] but String[][][] will not.

Examples

You can use:

  • String instead of java.lang.String
  • List instead of java.util.List
  • but not String* instead of java.lang.String or java.lang.StringBuffer
  • and so on...

Apart from these abbreviations you always have to specify the fully qualified name of the class (along with the wildcards).

Pointcut definition

The pointcut is a construct that picks out join points, i.e. selects well-defined points in the program flow.

The following types of pointcuts are currently supported:

  • execution(<method or constructor pattern>) - picks out join points defining method (static or member) or constructor execution.

    Valid advice for this pointcut are around, before and after.


  • call(<method or constructor pattern>) - picks out join points defining method (static or member) or constructor call.

    Valid advice for this pointcut are around, before and after.


  • set(<field pattern>) - picks out join points defining field modification.

    Valid advice for this pointcut are around, before and after.


  • get(<field pattern>) - picks out join points defining field access.

    Valid advice for this pointcut are around, before and after.


  • args(<type pattern or parameter name reference or greedy ".." pattern> [, <etc>]*) - picks out parameter types and optionnaly bind them as pointcut parameters.

    This pointcut has several usage that can be mixed together, but be carefull at not mixin several args() pointcut together in logical expression.

    First it can be used to filter method/constructor parameters types and field set field type. The special ".." pattern is used to match as many parameters as possible and should only be used once.

    execution(* method(..)) AND args(String, com.Bar[]) is equivalent to execution(* method(String, com.Bar[]) though it provides a better decomposition and could be split using pointcut references in something like myMethodsExecution AND args(String, com.Bar[]).

    Be carefull since call(* method(String)) AND args(String, int) will match .. nothing !

    set(* Bar.m_field) AND args(String) will match the String Bar.m_field field set.

    Second it can be used to retrieve and keep references to target method/constructor parameters and field value beeing set. For such a usage, the pointcut itself will be required to have a signature.

    myPointcut(String s) defined with execution(* method(..)) AND args(s) will thus match "method(String)" and moreover will further reference the parameter value of s. The advice will use this parameter in its own signature. void myBeforeAdvice(JoinPoint, String as) could thus be bounded to myPointcut(as). In this syntax, you have to be very cautious about the parameter name, here "s" in the pointcut signature and args() expression as well as "as" (could be s or "whatYouWant") in the advice and the advice binding expression.

    If you are interested in getting the first and last parameter, no matter the number and types of parameters in between, the special .. greedy pattern can then be used like in myPointcut(String argLast, int argFirst) defined with execution(* method(..)) AND args(argFirst, .., argLast). In this sample, you will notice that the pointcut signature is not required to respect the parameter order, though it is a bit error prone.

    Last args() can be use to both match parameter types and retain their values like in myPointcut(String s) defined with execution(* method(String, ..)) AND args(s, int, com.Bar, StringBuffer[][]). In such an expression, you will have noticed that we have to fully define the com.Bar type, while abbreviations for java.lang.* could be used (see the previous part for a note on abbreviations).



  • handler(<exception type pattern>) - picks out join points definining a catch clause.

    Valid advice for this pointcut is before.


  • cflow(<pointcut expression>) - picks out join points defining a control flow (cflow).

    This pointcut can only be used on conjunction with other pointcut types in an algebraic AND expression.


  • within(<type pattern>) - picks out a type set.

    This pointcut can be used when you need to limit the scope on which join points you pick out. It is really useful (and for most cases necessary) to use together with call and handler pointcuts.

    It can be used with other pointcuts as well (execution, get/set) to narrow the scope of the pointcut. For example, execution(* method(..)) will match all methods in all classes but execution(* method(..)) AND within(com.Foo) will match only in the com.Foo class.


  • withincode(<method or constructor pattern>) - picks out a method or constructor set.

    This pointcut can be used when you need to limit the scope on which join points you pick out. Really useful (and and most cases necessary) to use together with call and handler pointcuts.


  • hasmethod(<method or constructor pattern>) - picks out a class that has at least one method or constructor that match the given pattern.

    This pointcut can be used when you need to limit the scope on which join points you pick out based on a structural information of the class in which the join point may appear. This pointcut is similar to within - that is for example: hasmethod(* com.Foo.*(..)) is equivalent to within(com.Foo) unless the com.Foo class has no method at all.


  • hasfield(<field pattern>) - picks out a class that has at least one field that match the given pattern.

    This pointcut can be used when you need to limit the scope on which join points you pick out based on a structural information of the class in which the join point may appear. This pointcut is similar to within

Pointcuts can either defined:

  • explicitly - by giving them a name, this is done differently in the XML and the Annotation definitions.


  • anonymously - directly bound to an advice and/or as part of a pointcut composition expression. `
There is one exception: the XML syntax does not allow for anonymous pointcut with an args() selector. The pointcut with a signature must be named (so that the named paramter in args() can be referenced in its signature).

Pointcut composition

AspectWerkz supports pointcut composition, which means that poincuts can be composed. To compose pointcut expressions you can use these logical operators:

  • ! or NOT - logical not


  • || or OR - logical or


  • && or AND - logical and


  • parenthesis for grouping
In the XML definition the operator AND is more convenient (else & has to be escaped).

Using these operators together with parenthesis you can form any kind of algebraic expression. The model is highly orthogonal since all it allows you to mix any type of pointcut when composing new pointcuts.

!, NOT or not also works in conjunction with modifiers. For example: !public * *..*.*(..) for picking out all non-public methods.

Examples:

execution(* foo.bar.Baz.*(..)) || call(* foo.bar.Baz.*(..))

(set(* foo.bar.*) || get(* foo.bar.*)) && withincode(* foo.bar.Buzz.*(..))

handler(java.lang.Exception+) && !cflow(call(* foo.bar.Buzz.(..)))

call(!public !static * *..*.*(..))

call(NOT public NOT static * *..*.*(..))
                

Pointcut references

You can define pointcuts in one aspect definition (in XML or in annotations) and the refer to this pointcut in another aspect definition.

This can be very useful when building up pointcut libraries that you want to use throughout the projects or multiple projects.

You are referring to the external pointcut by using the aspect name (the full name of the aspect class if not a custom name has been defined) followed by a dot and then the pointcut name. For example: mylib.J2EEPointcuts.sessionBeans

Example:

<aspect class="foo.bar.MyAspect>
    <pointcut name="transactedSessionBeanMethods"
              expression="call(@Transaction * *..*.*(..)) && within(mylib.J2EEPointcuts.sessionBeans)"/>
    ...
</aspect>
                

Pluggable container implementation

You have the possibility of providing your own aspect container implementation. This can be useful if you need to control how your aspects are instantiated. (For example if you want to have them working with an IoC container (Spring, PicoContainer etc.))

To create a custom container you only need to implement the org.codehaus.aspectwerkz.aspect.AspectContainer interface, but it can be very beneficial to extend the org.codehaus.aspectwerkz.aspect.AbstractAspectContainer abstract base class (and only implement the abstract method Object createAspect()).

You specify which aspect should use which container in the XML definition using the container element.

Example:

<aspect class="foo.bar.Baz" container="org.codehaus.aware.container.SpringAspectContainer">
    ...
</aspect>
                

If you don't provide a custom implementation the default one will be used.

For a complete example on how to write your own custom aspect container take a look at the SpringAspectContainer documentation (and sources).

AOP system

Deployed aspects belongs to an aspect system. For now AspectWerkz support only a single system in the whole JVM. Aspect systems are named in the XML definition file and each system must have a unique name. The system name ( id) is used when accessing system at runtime, for example when redefining the aspect system.

Example:

<aspectwerkz>
    <system id="system name">
        <aspect name="MyAspect1"/>
        <aspect name="MyAspect2"/>
        ...
    </system>
</aspectwerkz>
                

Sample to access the system(s) at runtime

AspectSystem system = SystemLoader.getSystem(targetInstance);

AspectSystem system = SystemLoader.getSystem(targetClass);

AspectSystem system = SystemLoader.getSystem(classLoader);

Collection systems = SystemLoader.getAllSystems();
                

Passing parameters to aspects

You also have the option of passing parameters to your aspects. This can be very convenient if you want to reuse the same aspect but with a different configuration without using aspect inheritance. To pass a parameter to the aspect you simply add a param tag to the aspect definition, like this:

<aspect ... >
    <param name="timeout" value="10"/>
</aspect>
                

To retrieve the parameter (from within an aspect) use CrossCuttingInfo.getInfo("systemId", this).getParameter("timeout") to retrieve the parameter value as a String.

To set a new (or override) a parameter (from within an aspect) use CrossCuttingInfo.getInfo("systemId", this).setParameter("timeout", "10") to retrieve the parameter value as a String.

Deployment models

AspectWerkz supports four different deployment models, which defines the scope of the Aspect.

The four different deployment models are:

  • perJVM - one sole instance per JVM. Basically the same thing as a singleton class.


  • perClass - one instance per class.


  • perInstance - one instance per class instance.


  • perThread - one instance per thread.

Since introduction implementation are inner classes, they have to follow a subset of the aspect's deployment model. If not specified, the introduction is deployed as the aspect that defines it. Else the following applies:

Introduction deployment modelrequired Aspect deployment model
perJVMperJVM (default for Aspect)
perClassperJVM or perClass
perInstanceperinstance or perClass or perJVM
perThreadperThread