Table of Contents

General definition issues

This section documents the pointcut language, and goes thru advanced configuration concepts like pluggable aspect container and handling multiple AOP systems.

  1. Join point selection pattern language
  2. Pointcut definition
  3. Pointcut composition
  4. Pointcut references
  5. Pluggable container implementation
  6. AOP system
  7. Passing parameters to aspects
  8. Deployment models

Join point selection pattern language

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

Wildcards

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.


  • .. - used either to match any sequence of characters that start and end with a "." (so it can be used to pick out all types in any subpackage) or in method selectors to match as many parameters as possible.

    For example org.codehaus..* will match all classes in all subpackages starting from org.codehaus.

    * method(..) will match all methods with any number of parameters.
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.

Another specific character to express inheritance based matching will be presented further.

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>

Example of a full class pattern:

<annotations> <modifiers> <package_and_class_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.

Note that in the previous sample, foo.Bar can be wether a class (a super class) or an interface.

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 java.lang.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.

Two extra specific abbreviations are in place: JoinPoint will be resolved as org.codehaus.aspectwerkz.joinpoint.JoinPoint and StaticJoinPoint will be resolved as org.codehaus.aspectwerkz.joinpoint.StaticJoinPoint.

This is usefull when dealing with complex advice signature in the XML definition.

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.

staticinitialization() pointcut

staticinitialization(<type pattern>) - picks out join points defining class static initialization.

execution() pointcut

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

call() pointcut

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

set() pointcut

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

get() pointcut

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

handler() pointcut

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

Valid advice for this pointcut is before.

within() pointcut

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 ( staticinitialization, 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() pointcut

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

withincode(staticinitialization(<type pattern>)) - picks out a static class initalizer 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, get, set and handler pointcuts.

args() pointcut

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 forms 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).

target() and this() pointcuts

target(<type pattern or parameter name reference>) - picks out the target (callee) instance type and optionnaly bind it as pointcut parameter.

this(<type pattern or parameter name reference>) - picks out the this (caller) instance type and optionnaly bind it as pointcut parameter.

this(..) and target(..) pointcut designators can be used to narrow a pointcut expression based on caller and calle types or to gain access to those in the advice signature without any casting or reflective access.

Note that they will implictly filter out callee side static methods, callee constructors on constructor call pointcut (since the callee is not available yet), and caller side static method for call pointcuts and field pointcuts.

First, when used with type patterns: target(foo.*), this(foo.Bar+), etc, they will filter respectively callee and caller types.

Second, when used with a paramter binding, they will allow to gain direct access to respectively callee (target) and caller (this) instance in advice by using advice argument binding, when combined with pointcut with signature or advice with signature (see previous part).

// this pointcut is not declared as a field since it exposes parameter binding
// note use of "bar" variable name
@Expression("target(bar)")
void pointcut(Bar bar) {}

// use the pointcut with respect to its signature
// note use of "myBar" variable name
@Before("execution(* *..method(..)) && pointcut(myBar)")
void before(Bar myBar) {
    myBar.callback();
}
                

cflow() pointcut

cflow(<pointcut expression>) - picks out join points defining a control flow (cflow). Note: the nested pointcut expression must not bind parameters. args(), this() and target() can be used with typed expression only (ie statefull cflow is not yet supported). Nested cflow() can be used.

hasmethod() pointcut

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() pointcut

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

Named or anonymous pointcuts

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:

  • ! - 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.

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

Examples:

staticinitialization(foo..*) && within(@AnnotatedFoo)

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 * *..*.*(..))
                

Pointcut references

You can define pointcuts in one aspect definition (in XML or in annotations) and then 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>
                

Note that you can only reference pointcut from Aspects defined within the same AOP system.

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 belong to an aspect system. The system provides namespace isolation and is ClassLoader aware. Aspect systems are named in the XML definition file and each system must have a unique name within a ClassLoader hierarchy. This is a good practice to use a package naming convention for naming your system. The system name ( id) is used when accessing system at runtime, for example when redefining the aspect system.

Example:

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

Sample to access the system(s) at runtime

SystemDefinition system = SystemDefinition.getDefinitionFor(classLoader, id);

Set<SystemDefinition> systems = SystemDefinition.getDefinitionsFor(classLoader);
                

Systems follow ClassLoader rules.

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 AspectContext.getParameter("timeout") to retrieve the parameter value as a String.

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

Deployment models

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

The three different deployment models for Aspects 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.

The three different deployment models for Mixins are:

  • perInstance - one instance per class instance.


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

The deployment model can be specified using the @Aspect or @Mixin annotation or using the XML definition. Refer to the sections covering Annotation or XML definitions.