Pointcuts

A pointcut is a program element that picks out join points, as well as data from the execution context of the join points. Pointcuts are used primarily by advice. They can be composed with boolean operators to build up other pointcuts. So a pointcut is defined by one of

call(Signature)

Picks out a method or constructor call join point based on the static signature at the caller side.

execution(Signature)

Picks out a method or constructor execution join point based on the static signature at the callee side.

get(Signature)

Picks out a field get join point based on the static signature. Note that references to constant fields (static final fields bound to a constant string object or primitive value) are not get join points, since Java requires them to be inlined.

set(Signature)

Picks out a field set join point based on the static signature. Note that the initializations of constant fields (static final fields where the initializer is a constant string object or primitive value) are not set join points, since Java requires their references to be inlined.

handler(TypePattern)

Picks out an exception handler of any of the Throwable types of the type pattern.

initialization(Signature)

Picks out an object initialization join point based on the static signature of the starting constructor.

staticinitialization(TypePattern)

Picks out a static initializer execution join point of any of the types of the type pattern.

within(TypePattern)

Picks out all join points where the executing code is defined in any of the classes of the type pattern.

withincode(Signature)

Picks out all join points where the executing code is defined in the method or constructor of the appropriate signature.

cflow(Pointcut)

Picks out all join points in the control flow of the join points picked out by the pointcut, including pointcut's join points themselves.

cflowbelow(Pointcut)

Picks out all join points in the control flow below the join points picked out by the pointcut.

this(TypePattern or Id)

Picks out all join points where the currently executing object (the object bound to this) is an instance of a type of the type pattern, or of the type of the identifier. Will not match any join points from static methods.

target(TypePattern or Id)

Picks out all join points where the target object (the object on which a call or field operation is applied to) is an instance of a type of the type pattern, or of the type of the identifier. Will not match any calls, gets, or sets to static members.

args(TypePattern or Id, ...)

Picks out all join points where the arguments are instances of a type of the appropriate type pattern or identifier.

PointcutId(TypePattern or Id, ...)

Picks out all join points that are picked out by the user-defined pointcut designator named by PointcutId.

if(BooleanExpression)

Picks out all join points where the boolean expression evaluates to true. The boolean expression used can only access static members, variables exposed by teh enclosing pointcut or advice, and thisJoinPoint forms. In particular, it cannot call non-static methods on the aspect.

! Pointcut

Picks out all join points that are not picked out by the pointcut.

Pointcut0 && Pointcut1

Picks out all join points that are picked out by both of the pointcuts.

Pointcut0 || Pointcut1

Picks out all join points that are picked out by either of the pointcuts.

( Pointcut )

Picks out all join points that are picked out by the parenthesized pointcut.

Pointcut naming

A named pointcut is defined with the pointcut declaration.

pointcut publicIntCall(int i):
    call(public * *(int)) && args(i);

A named pointcut may be defined in either a class or aspect, and is treated as a member of the class or aspect where it is found. As a member, it may have an access modifier such as public or private.

class C {
    pointcut publicCall(int i):
        call(public * *(int)) && args(i);
}

class D {
    pointcut myPublicCall(int i):
        C.publicCall(i) && within(SomeType);
}

Pointcuts that are not final may be declared abstract, and defined without a body. Abstract pointcuts may only be declared within abstract aspects.

abstract aspect A {
    abstract pointcut publicCall(int i);
}

In such a case, an extending aspect may override the abstract pointcut.

aspect B extends A {
    pointcut publicCall(int i): call(public Foo.m(int)) && args(i);
}

For completeness, a pointcut with a declaration may be declared final.

Though named pointcut declarations appear somewhat like method declarations, and can be overridden in subaspects, they cannot be overloaded. It is an error for two pointcuts to be named with the same name in the same class or aspect declaration.

The scope of a named pointcut is the enclosing class declaration. This is different than the scope of other members; the scope of other members is the enclosing class body. This means that the following code is legal:

aspect B percflow(publicCall()) {
    pointcut publicCall(): call(public Foo.m(int));
}

Context exposure

Pointcuts have an interface; they expose some parts of the execution context of the join points they pick out. For example, the PublicIntCall above exposes the first argument from the receptions of all public unary integer methods. This context is exposed by providing typed formal parameters to named pointcuts and advice, like the formal parameters of a Java method. These formal parameters are bound by name matching.

On the right-hand side of advice or pointcut declarations, a regular Java identifier is allowed in certain pointcut designators in place of a type or collection of types. There are four primitive pointcut designators where this is allowed: this, target, and args. In all such cases, using an identifier rather than a type is as if the type selected was the type of the formal parameter, so that the pointcut

pointcut intArg(int i): args(i);

picks out join points where an int is being passed as an argument, but furthermore allows advice access to that argument.

Values can be exposed from named pointcuts as well, so

pointcut publicCall(int x): call(public *.*(int)) && intArg(x);
pointcut intArg(int i): args(i);

is a legal way to pick out all calls to public methods accepting an int argument, and exposing that argument.

There is one special case for this kind of exposure. Exposing an argument of type Object will also match primitive typed arguments, and expose a "boxed" version of the primitive. So,

pointcut publicCall(): call(public *.*(..)) && args(Object);

will pick out all unary methods that take, as their only argument, subtypes of Object (i.e., not primitive types like int), but

pointcut publicCall(Object o): call(public *.*(..)) && args(o);

will pick out all unary methods that take any argument: And if the argument was an int, then the value passed to advice will be of type java.lang.Integer.

Primitive pointcuts

Method-related pointcuts

AspectJ provides two primitive pointcut designators designed to capture method call and execution join points.

call(Signature)
execution(Signature)

These two pointcuts also pick out constructor call end execution join points.

Field-related pointcuts

AspectJ provides two primitive pointcut designators designed to capture field reference and assignment join points:

get(Signature)
set(Signature)

All set join points are treated as having one argument, the value the field is being set to, so at a set join point, that value can be accessed with an args pointcut. So an aspect guarding an integer variable x declared in type T might be written as

aspect GuardedX {
    static final int MAX_CHANGE = 100;
    before(int newval): set(int T.x) && args(newval) {
        if (Math.abs(newval - T.x) > MAX_CHANGE)
            throw new RuntimeException();
    }
}

Object creation-related pointcuts

AspectJ provides three primitive pointcut designators designed to capture the initializer execution join points of objects.

call(Signature)
initialization(Signature)
execution(Signature)

Class initialization-related pointcuts

AspectJ provides one primitive pointcut designator to pick out static initializer execution join points.

staticinitialization(TypePattern)

Exception handler execution-related pointcuts

AspectJ provides one primitive pointcut designator to capture execution of exception handlers:

handler(TypePattern)

All handler join points are treated as having one argument, the value of the exception being handled, so at a handler join point, that value can be accessed with an args pointcut. So an aspect used to put FooException objects into some normal form before they are handled could be written as

aspect NormalizeFooException {
    before(FooException e): handler(FooException) && args(e) {
        e.normalize();
    }
}

State-based pointcuts

Many concerns cut across the dynamic times when an object of a particular type is executing, being operated on, or being passed around. AspectJ provides primitive pointcuts that capture join points at these times. These pointcuts use the dynamic types of their objects to discriminate, or pick out, join points. They may also be used to expose to advice the objects used for discrimination.

this(TypePattern or Id)
target(TypePattern or Id)

The this pointcut picks out all join points where the currently executing object (the object bound to this) is an instance of a particular type. The target pointcut picks out all join points where the target object (the object on which a method is called or a field is accessed) is an instance of a particular type.

args(TypePattern or Id or "..", ...)

The args pointcut picks out all join points where the arguments are instances of some types. Each element in the comma-separated list is one of three things. If it is a type pattern, then the argument in that position must be an instance of a type of the type name. If it is an identifier, then the argument in that position must be an instance of the type of the identifier (or of any type if the identifier is typed to Object). If it is the special wildcard "..", then any number of arguments will match, just like in signatures. So the pointcut

args(int, .., String)

will pick out all join points where the first argument is an int and the last is a String.

Control flow-based pointcuts

Some concerns cut across the control flow of the program. The cflow and cflowbelow primitive pointcut designators capture join points based on control flow.

cflow(Pointcut)
cflowbelow(Pointcut)

The cflow pointcut picks out all join points that occur between the start and the end of each of the pointcut's join points.

The cflowbelow pointcut picks out all join points that occur between the start and the end of each of the pointcut's join points, but not including the initial join point of the control flow itself.

Program text-based pointcuts

While many concerns cut across the runtime structure of the program, some must deal with the actual lexical structure. AspectJ allows aspects to pick out join points based on where their associated code is defined.

within(TypePattern)
withincode(Signature)

The within pointcut picks out all join points where the code executing is defined in the declaration of one of the types in TypePattern. This includes the class initialization, object initialization, and method and constructor execution join points for the type, as well as any join points associated with the statements and expressions of the type. It also includes any join points that are associated with code within any of the type's nested types.

The withincode pointcut picks out all join points where the code executing is defined in the declaration of a particular method or constructor. This includes the method or constructor execution join point as well as any join points associated with the statements and expressions of the method or constructor. It also includes any join points that are associated with code within any of the method or constructor's local or anonymous types.

Dynamic property-based pointcuts

if(BooleanExpression)

The if pointcut picks out join points based on a dynamic property. It's syntax takes an expression, which must evaluate to a boolean true or false. Within this expression, the thisJoinPoint object is available. So one (extremely inefficient) way of picking out all call join points would be to use the pointcut

if(thisJoinPoint.getKind().equals("call"))

Signatures

One very important property of a join point is its signature, which is used by many of AspectJ's pointcut designators to select particular join points.

At a method call join point, the signature is composed of the type used to access the method, the name of the method, and the the types of the called method's formal parameters and return value (if any).

At a method execution join point, the signature is composed of the type defining the method, the name of the method, and the the types of the executing method's formal parameters and return value (if any).

At a constructor call join point, the signature is composed of the type of the object to be constructed and the types of the called constructor's formal parameters.

At a constructor execution join point, the signature is composed of the type defining the constructor and the types of the executing constructor's formal parameters.

At an object initialization join point, the signature is composed of the type being initialized and the types of the formal parameters of the first constructor entered during the initialization of this type.

At an object pre-initialization join point, the signature is composed of the type being initialized and the types of the formal parameters of the first constructor entered during the initialization of this type.

At a field reference or assignment join point, the signature is composed of the type used to access or assign to the field, the name of the field, and the type of the field.

At a handler execution join point, the signature is composed of the exception type that the handler handles.

The withincode, call, execution, get, and set primitive pointcut designators all use signature patterns to determine the join points they describe. A signature pattern is an abstract description of one or more join-point signatures. Signature patterns are intended to match very closely the same kind of things one would write when defining individual methods and constructors.

Method definitions in Java include method names, method parameters, return types, modifiers like static or private, and throws clauses, while constructor definitions omit the return type and replace the method name with the class name. The start of a particular method definition, in class Test, for example, might be

class C {
    public final void foo() throws ArrayOutOfBoundsException { ... }
}

In AspectJ, method signature patterns have all these, but most elements can be replaced by wildcards. So

call(public final void C.foo() throws ArrayOutOfBoundsException)

picks out call join points to that method, and the pointcut

call(public final void *.*() throws ArrayOutOfBoundsException)

picks out all call join points to methods, regardless of their name name or which class they are defined on, so long as they take no arguments, return no value, are both public and final, and are declared to throw ArrayOutOfBounds exceptions.

The defining type name, if not present, defaults to *, so another way of writing that pointcut would be

call(public final void *() throws ArrayOutOfBoundsException)

Formal parameter lists can use the wildcard .. to indicate zero or more arguments, so

execution(void m(..))

picks out execution join points for void methods named m, of any number of arguments, while

execution(void m(.., int))

picks out execution join points for void methods named m whose last parameter is of type int.

The modifiers also form part of the signature pattern. If an AspectJ signature pattern should match methods without a particular modifier, such as all non-public methods, the appropriate modifier should be negated with the ! operator. So,

withincode(!public void foo())

picks out all join points associated with code in null non-public void methods named foo, while

withincode(void foo())

picks out all join points associated with code in null void methods named foo, regardless of access modifier.

Method names may contain the * wildcard, indicating any number of characters in the method name. So

call(int *())

picks out all call join points to int methods regardless of name, but

call(int get*())

picks out all call join points to int methods where the method name starts with the characters "get".

AspectJ uses the new keyword for constructor signature patterns rather than using a particular class name. So the execution join points of private null constructor of a class C defined to throw an ArithmeticException can be picked out with

execution(private C.new() throws ArithmeticException)

Type patterns

Type patterns are a way to pick out collections of types and use them in places where you would otherwise use only one type. The rules for using type patterns are simple.

Type name patterns

First, all type names are also type patterns. So Object, java.util.HashMap, Map.Entry, int are all type patterns.

There is a special type name, *, which is also a type pattern. * picks out all types, including primitive types. So

call(void foo(*))

picks out all call join points to void methods named foo, taking one argument of any type.

Type names that contain the two wildcards "*" and ".." are also type patterns. The * wildcard matches zero or more characters characters except for ".", so it can be used when types have a certain naming convention. So

handler(java.util.*Map)

picks out the types java.util.Map and java.util.java.util.HashMap, among others, and

handler(java.util.*)

picks out all types that start with "java.util." and don't have any more "."s, that is, the types in the java.util package, but not inner types (such as java.util.Map.Entry).

The ".." wildcard matches any sequence of characters that start and end with a ".", so it can be used to pick out all types in any subpackage, or all inner types. So

target(com.xerox..*)

picks out all join points where the target object is an instance of defined in any type beginning with "com.xerox.".

Subtype patterns

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

call(Foo.new())

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

call(Foo+.new())

picks out all constructor call join points where an instance of any subtype of Foo (including Foo itself) is constructed, and the unlikely

call(*Handler+.new())

picks out all constructor call join points where an instance of any subtype of any type whose name ends in "Handler" 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 com.xerox..*[][], and so is Object+[].

Type patterns

Type patterns are built up out of type name patterns, subtype patterns, and array type patterns, and constructed with boolean operators &&, ||, and !. So

staticinitialization(Foo || Bar)

picks out the static initializer execution join points of either Foo or Bar, and

call((Foo+ && ! Foo).new(..))

picks out the constructor call join points when a subtype of Foo, but not Foo itself, is constructed.

Pointcuts and Join Points

It is possible to pick out every different kind of join point with pointcuts, but some of the less common ones require pointcut combination.

Method call

aspect A {
    after() returning: call(void foo()) {
        System.err.println(thisJoinPoint.getKind()); // should be "method-call"
    }
}

Method execution

aspect A {
    after() returning: execution(void foo()) {
        System.err.println(thisJoinPoint.getKind()); // should be "method-execution"
    }
}

Constructor call

aspect A {
    after() returning: call(Foo.new()) {
        System.err.println(thisJoinPoint.getKind()); // should be "constructor-call"
    }
}

Constructor execution

aspect A {
    after() returning: execution(Foo.new()) {
        System.err.println(thisJoinPoint.getKind()); // should be "constructor-execution"
    }
}

Static initializer execution

aspect A {
    after() returning: staticinitializer(Foo) {
        System.err.println(thisJoinPoint.getKind()); // should be "static-initializar"
    }
}

Object pre-initialization

This join point will most commonly be seen as the enclosing execution join point of a particular call, since it cannot be simply picked out by AspectJ's primitive pointcuts.

aspect A {
    after() returning: call(Foo) {
        System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "pre-initialization"
    }
}

Object initialization

aspect A {
    after() returning: initialization(Foo.new()) {
        System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "initialization"
    }
}

Field Reference

aspect A {
    after() returning: get(Foo.x) {
        System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "field-get"
    }
}

Field Assignment

aspect A {
    after() returning: set(Foo.x) {
        System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "field-set"
    }
}

Handler Execution

aspect A {
    after() returning: handler(FooExn) {
        System.err.println(thisEnclosingJoinPointStaticPart.getKind()); // should be "handler"
    }
}