Advice

before(Formals): Pointcut { Body }
after(Formals) returning [ (Formal) ]: Pointcut { Body }
after(Formals) throwing [ (Formal) ]: Pointcut { Body }
after(Formals) : Pointcut { Body }
Type around(Formals) [ throws TypeList ] : Pointcut { Body }

Advice defines crosscutting behavior. It is defined in terms of pointcuts. The code of a piece of advice runs at every join point picked out by its pointcut. Exactly how the code runs depends on the kind of advice.

AspectJ supports three kinds of advice. The kind of advice determines how it interacts with the join points it is defined over. Thus AspectJ divides advice into that which runs before its join points, that which runs after its join points, and that which runs in place of (or "around") its join points.

While before advice is relatively unproblematic, there can be three interpretations of after advice: After the execution of a join point completes normally, after it throws an exception, or after it does either one. AspectJ allows after advice for any of these situations.

aspect A {
    pointcut publicCall(): call(public Object *(..));
    after() returning (Object o): publicCall() {
        System.out.println("Returned normally with " + o);
    }
    after() throwing (Exception e): publicCall() {
        System.out.println("Threw an exception: " + e);
    }
    after(): publicCall(){
        System.out.println("Returned or threw an Exception");
    }
}

After returning advice may not care about its returned object, in which case it may be written

after() returning: call(public Object *(..)) {
    System.out.println("Returned normally");
}

It is an error to try to put after returning advice on a join point that does not return the correct type. For example,

after() returning (byte b): call(int String.length()) {
    // this is an error
}

is not allowed. But if no return value is exposed, or the exposed return value is typed to Object, then it may be applied to any join point. If the exposed value is typed to Object, then the actual return value is converted to an object type for the body of the advice: int values are represented as java.lang.Integer objects, etc, and no value (from void methods, for example) is represented as null.

In some cases, more control over a pointcut is needed than before or after advice can give. Around advice runs in place of the join point it operates over, rather than before or after it.

Because around is allowed to return a value, it must be declared with a return type, like a method. A piece of around advice may be declared void, in which case it is not allowed to return a value, and instead whatever value the join point returned will be returned by the around advice (unless the around advice throws an exception of its own).

Thus, a simple use of around advice is to make a particular method constant:

aspect A {
    int around(): call(int C.foo()) {
        return 3;
    }
}

Within the body of around advice, though, the computation of the original join point can be executed with the special syntax

proceed( ... )

The proceed form takes as arguments the context exposed by the around's pointcut, and returns whatever the around is declared to return. So the following around advice will double the second argument to foo whenever it is called, and then halve its result:

aspect A {
    int around(int i): call(int C.foo(Object, int)) && args(i) {
        int newi = proceed(i*2)
        return newi/2;
    }
}

If a piece of around advice is typed to Object, then the result of proceed is converted to an object representation, even if it is originally a primitive value. And the return value is converted back to whatever representation it was originally.

In all kinds of advice, the parameters of the advice behave exactly like method parameters. In particular, assigning to any parameter affects only the value of the parameter, not the value that it came from. This means that

aspect A {
    after() returning (int i): call(int C.foo()) {
        i = i * 2;
    }
}

will not double the returned value of the advice. Rather, it will double the local parameter. Changing the values of parameters or return values of join points can be done by using around advice.

Advice modifiers

Only one modifier is allowed on advice: The strictfp modifier. As with method declarations, all floating-point expressions are FP-strict inside a strictfp piece of advice

Advice precedence

Multiple pieces of advice may apply to the same join point. In such cases, the resolution order of the advice is based on advice precedence.

Determining precedence

There are a number of rules that determine whether a particular piece of advice has precedence over another when they advise the same join point.

If the two pieces of advice are defined in different aspects, then there are three cases:

If aspect A is declared such that it dominates aspect B, then all advice defined in A has precedence over all advice defined in B.

Otherwise, if aspect A is a strict subaspect of aspect B, then all advice defined in A has precedence over all advice defined in B. That is, unless otherwise specified with a dominates keyword, advice in a subaspect dominates advice in a superaspect.

Otherwise, if two pieces of advice are defined in two different aspects, it is undefined which one has precedence.

If the two pieces of advice are defined in the same aspect, then there are two cases:

If either are after advice, then the one that appears later in the aspect has precedence over the one that appears earlier.

Otherwise, then the one that appears earlier in the aspect has precedence over the one that appears later.

These rules can lead to circularity, such as

aspect A {
    before(): execution(void main(String[] args)) {}
    after():  execution(void main(String[] args)) {}
    before(): execution(void main(String[] args)) {}
}

such circularities are compile-time errors.

Effects of precedence

At a particular join point, advice is ordered by precedence.

A piece of around advice can control when (and whether) advice of lower precedence will run, by calling proceed. The call to proceed will run the advice with next highest precedence, or the computation under the join point if there is no further advice.

A piece of before advice can prevent advice of lower precedence from running by throwing an exception. If it returns normally, however, then the advice of the next highest precedence, or the computation under the join pint if there is no further advice, will run next.

Running after returning advice will run the advice of next highest precedence, or the computation under the join point if there is no further advice. Then, if that computation returned normally, the body of the advice will run.

Running after throwing advice will run the advice of next highest precedence, or the computation under the join point if there is no further advice. Then, if that computation threw an exception of an appropriate type, the body of the advice will run.

Running after advice will run the advice of next highest precedence, or the computation under the join point if there is no further advice. Then the body of the advice will run.

Reflective access to the join point

Two special variables are visible within bodies of advice: thisJoinPoint and thisJoinPointStaticPart. Each is bound to an object that encapsulates some of the context of the advice's current join point. These variables exist because some pointcuts may pick out very large collections of join points. For example, the pointcut

pointcut publicCall(): call(public * *(..));

picks out calls to many methods. Yet the body of advice over this pointcut may wish to have access to the method name or parameters of a particular join point.

thisJoinPoint is bound to a complete join point object, while thisJoinPointStaticPart is bound to a part of the join point object that includes less information, but for which no memory allocation is required on each execution of the advice.

Join point objects are built up of reflective objects in the spirit of the java.lang.reflect hierarchy. thisJoinPoint is bound to objects of interface type org.aspectj.lang.JoinPoint, while thisStaticJoinPoint is bound to objects of interface type org.aspectj.lang.JoinPoint.StaticPart.