Quick Reference Guide
Aspects
Aspects in SpoonAOP are pure Java classes that extend Aspect. Aspect is a Spoon template that define template parameters that are filled up with the currently tested joinpoint candidate (shadow) data. Inside an aspect, mixin methods, advices, and pointcut methods can access this information to express generic aspect behavior. The table below defines the template parameters defined in an aspect:
| Template Parameter | Meaning |
|---|---|
_argumentCount_ | number of arguments of the target executable. |
_argumentList_ | the list of arguments, which can be substituted as is when calling a template method taking a List<CtParameter>. |
_arguments_ | arguments (parameter accesses) of the target executable (both for reading and writing). |
_argumentTypes_ | types of the arguments of the target executable. |
_caller_ | the caller's instance when available and when the advised executable is not static (call-side only). |
_callerClass_ | the class of the caller (call-side only). |
_callerName_ | the name of the calling executable (call-side only). |
_callerTypeName_ | the qualified name of the caller type (call-side only). |
_org_ | the block of code that corresponds to the original code of the target executable. |
_return_ | accesses to the local variable that holds the returned value of the target executable. |
_returnType_ | return type of the target executable. |
_target_ | the target instance (equals to this at execution side). |
_targetClass_ | the class of the target. |
_targetName_ | the name of the target executable. |
_targetTypeName_ | the qualified name of the target type. |
Advices
Advices are defines as normal Java methods within an aspect, except that they must be annotated with one of the following annotations:
| Advice annotation | Meaning |
|---|---|
Before(side=Side.CALL|Side.EXECUTION) | the advice code is inlined before the target executable's invocation (CALL) or execution (EXECUTION). |
After(side=Side.CALL|Side.EXECUTION) | the advice code is inlined after the target executable's invocation (CALL) or before all the returns with an execution (EXECUTION). Note that the result of an invocation or execution is store in a local variable so that you can access the result via the _result_ template parameter. |
Replace(side=Side.CALL|Side.EXECUTION) | the code of the target method invocation (CALL) or execution (EXECUTION) is replaced by the advice code. Note that the advice code can ask for the substitution of the original target code by using _org_.S(). |
Introductions
Member (method or field) introductions are simply specified as being regular Java member within an aspect class. No annotations are needed to define introductions, however, the aspect must match to a given target type to actually activate the introduction mechanism (see the pointcut section for that). Members that are local to an aspect and should not be introduced must be annotated with the Local annotation.
On the other hand, type introductions are defined through annotations that must be applied to the aspect. Like for member introductions, the aspect must match to a given target type to actually activate the introduction mechanism (see the pointcut section for that). Type introductions are defined with the following annotations:
| Type introduction annotation | Meaning |
|---|---|
Implements(value={interfaces}) | the given list of interfaces are added to the target class. |
Extends(value=class) | the given class is set to be the superclass of the target class (replacing the current superclass if any). |
Pointcuts
In Spoon-AOP, you can write annotation-driven aspects in a straightforward way. The rule for an aspect element to be applied to a given target element is that the target element is annotated with the same annotation set as the aspect element. For advices, only the method-level annotations are taken into account, while for introductions, the class and aspect-level annotation are taken into account.
Annotation parameters' values can be bound to the aspect by declaring a static final template parameter. As an example, the following logging aspect binds the value of the Log parameter to _logLevel_ and uses it to advice only the methods where the logging level is greater than 0:
public class LoggingAspect extends Aspect {
@Parameter
static final int _logLevel_ = 0;
@Before(side=Side.CALL) @Log(LoggingAspect._logLevel_)
void log() {
if (_logLevel_>0) {
System.out.println("calling method " + _targetName_);
}
}
}
Pointcuts that do not depend on annotations can be simply written in pure Java by using statically known information available in the aspect. They are usually written as an if statement within the advice's body. Pointcuts can be factorized using boolean methods annotated with the Pointcut annotation.
For introductions, the aspect can define a type-level pointcut by overriding the typePointcut method. The following example shows a generic visitor aspect that introduces an accept method in all the subclasses of a given root class.
public class VisitorAspect extends Aspect {
@Override
protected boolean typePointcut() {
return Expression.class.isAssignableFrom(_targetClass_);
}
@Parameter
Class _Visitor_=PrintExpressionVisitor.class;
public void accept(_Visitor_ visitor) {
visitor.visit_targetTypeName_(this);
}
interface _Visitor_ {
void visit_targetTypeName_(Object e);
}
}

