Aspects

In AspectWerkz any Java class can be an aspect (or more conceptually correct, can be defined to be cross-cutting), which means that it will become a unit of modularity for crosscutting concerns.

They do not have to extend any special class or implement a specific interface, but can extend any class they want.

The only requirement is that the aspect needs to have either no constructor at all (meaning implicitly a default one) or one of these two different constructors defined:

  • a default no-argument constructor - only needed if the aspect has other constructors that takes parameters (apart from the one below if defined)


  • a constructor that takes a org.codehaus.aspectwerkz.AspectContext instance as its only parameter - this is needed if you want to retrieve information about the runtime system, access parameters defined at deployment time, access meta-data etc. See Using the AspectContext class section for details.


AspectWerkz will try to use firstly the constructor of type 2. If not found than the default constructor will be used. If no default constructor is found then an exception is thrown.

The aspect can then be defined using XML or annotations, see the XML definition section or the Annotation definition section for more information.

Abstract aspects - aspect inheritance

Since the Aspects are pure Java classes, you have the possibility of defining abstract aspects that you can reuse by implementing another aspect that inherits the abstract aspect.

Aspect inheritance is exactly regular class inheritance. An abstract aspect is defined using the abstract keyword as a regular abstract class and is inherited using the extends keyword.

Nevertheless specific rules must be observed for advices represented as methods. Indeed, the advice is likely to be invoked from the class it is applied to as a result of the weaving process. Advices should thus be public. Private or protected advices are not supported. Package private advices are not encouraged. Aspects classes should for the same purpose be public (or package private though not encouraged).

Advice

In the aspect class the advices are regular methods. The methods needs to conform to a specific signature unless args(), this() and/or target() selectors are used in the pointcut the advice is bounded to.

  • For Around advice:

    public Object <name of method>(StaticJoinPoint staticJoinPoint) throws Throwable signature.

    public Object <name of method>(JoinPoint joinPoint) throws Throwable signature.


  • For Before, After, After Finally, After Returning (TYPE) and After Throwing (TYPE) advice:

    public void <name of method>() signature.

    public void <name of method>(StaticJoinPoint staticJoinPoint) signature.

    public void <name of method>(JoinPoint joinPoint) signature.
The advice can then be defined using XML or annotations, see the XML definition section or the Annotation definition section for more information.

Using StaticJoinPoint, JoinPoint or no JoinPoint at all is discussed in this section.

Here is a simple example of an Around advice. (For more examples see the Examples section.) The JoinPoint object that is passed to the method contains metadata and RTTI of the current join point. To invoke the next advice in the chain (or the target method if there are no more advice) simply call joinPoint.proceed() which will return the result from the next advice (or the target method).

@Around("myPointcut")
public Object myAroundAdvice(JoinPoint joinPoint) throws Throwable {
    // do some stuff
    Object result = joinPoint.proceed();
    // do some more stuff
    return result;
}
            

Note: for such a simple advice, StaticJoinPoint and staticJoinPoint.proceed() would be preferable.

When using pointcut designators like args(..), this(..), target(..), or when using after returning or after throwing with a type binding, advice signature will be pointcut dependant. This allows to gain direct access to the advised method/constructor/field set arguments. The Pointcut declaration itself will have a specific signature. The bounded advice(s) is then required to have those parameters in their signature as well. This allows to avoid using the RTTI interface as well as providing strong typing and implies better performance.

Such an advice can be defined through Annotations and through XML. See the XML definition section or the Annotation definition section for more information.

The advice signature is thus depending on the pointcut signature and the use of JoinPoint, StaticJoinPoint, user defined JoinPoint or not use of it at all. A sample could look like the following:

// will match all method named "log" with a "java.lang.String" as sole parameter
@Expression("execution(* log(..)) AND args(s)")
Pointcut myPointcut(String s) {return null;}

@Before("myPointcut(adviceArg)")
public void myBeforeAdvice(JoinPoint joinPoint, String adviceArg) {...}

// it is possible to have the JoinPoint at any index in the advice parameter list
// though a best practice is to keep it at the first position
@Around("myPointcut(adviceArg)")
public Object myAroundAdvice(String adviceArg, StaticJoinPoint joinPoint) {... joinPoint.proceed(); ...}

// user defined JoinPoint (could extend StaticJoinPoint as well)
static interface MyJoinPoint extends JoinPoint {
   Object proceed(String adviceArgIdLikeToChange);
}
@Around("myPointcut(adviceArg)")
public Object myAroundAdvice(MyJoinPoint myJoinPoint) {
   ...
   myJoinPoint.proceed("new value !!");
   ...
}


@After("myPointcut(adviceArg)")
public void myAfterAdvice(JoinPoint joinPoint, String adviceArg) {...}
                

After advice semantics

In previous releases of AspectWerkz, we only supported one single type of after advice. The semantics of this type was that it was always executed, regardless of whether an exception had been thrown or if the method returned successfully.

In the new 2.x architecture we have enhanced the semantics for this type of advice and have borrowed the semantics from AspectJ. So now we support three different types of after advice:

  • @AfterFinally (same as @After)
  • @AfterReturning [TYPE] - @AfterReturing(pointcut) or @AfterReturning(type=onReturnedType, pointcut=pointcut)
  • @AfterThrowing [TYPE] - @AfterThrowing(pointcut) or @AfterThrowing(type=onThrownedType, pointcut=pointcut))

after finally (after)

An after finally advice declaration has the same semantics as an after advice declaration, you can use any syntax you like.

after finally advice are always executed, they work the same as a finally block (meaning that they will be invoked regardless of wheter an exception has been thrown or if the method has returned successfully).

Java 5 annotation definition

@AfterFinally("execution(@TransactionAttribute * *.*(..))")
public void logTxMethods(StaticJoinPoint joinPoint) {..}
                    

JavaDoc annotation definition

/**
 * @AfterFinally("execution(@TransactionAttribute * *.*(..))")
 */
public void logTxMethods(StaticJoinPoint joinPoint) {..}
                    

XML definition

<advice type="after finally"
        bind-to="execution(@TransactionAttribute * *.*(..))"
        name="logTxMethods"/>
                    

after returning [TYPE]

after returning [TYPE] advice are executed if the method returns normally (without throwing an exception) and the actual type that is returned is of the type that is specified in the advice declaration.

If no return type is specified then it applies to all invocations that return normally, e.g. not when throwing an exception.

Java 5 annotation definition

@AfterReturning(
    type="@Service *..*",
    pointcut="execution(@TransactionAttribute * *.*(..)"
)
public void txCommitReturningService(StaticJoinPoint joinPoint) {..}
                    

JavaDoc annotation definition

/**
 * @AfterReturning(
 *      type="@Service *..*",
 *      pointcut="execution(@TransactionAttribute * *.*(..)"
 * )
 */
public void txCommitReturningService(StaticJoinPoint joinPoint) {..}
                    

XML definition

<advice type="after returning(@Service *..*)"
        bind-to="execution(@TransactionAttribute * *.*(..))"
        name="txCommitReturningService"/>
                    

after throwing [TYPE]

after throwing [TYPE] advice is executed if the advised method returns with an exception and the actual type of the exception that was thrown is of the type that is specified in the advice declaration.

If no exception type is specified then it applies to all invocations that return with an exception.

Java 5 annotation definition

@AfterThrowing(
    type="RuntimeException",
    pointcut="execution(@TransactionAttribute * *.*(..)"
)
public void txRollbackOnRuntimeException(StaticJoinPoint joinPoint) {..}
                    

JavaDoc annotation definition

/**
 * @AfterThrowing(
 *    type="RuntimeException",
 *    pointcut="execution(@TransactionAttribute * *.*(..)"
 * )
 */
public void txRollbackOnRuntimeException(StaticJoinPoint joinPoint) {..}
                    

XML definition

<advice type="after throwing(RuntimeException)"
        bind-to="execution(@TransactionAttribute * *.*(..))"
        name="txRollbackOnRuntimeException"/>
                    

JoinPoint instance

Each advice is passed the JoinPoint instance or StaticJoinPoint instance if it requires it. The JoinPoint class implements the join point concept, i.e. a well-defined point in the program flow and provides a reflective access API to it. The StaticJoinPoint class is a lightweight version without the reflective access API which allows for a better performance (at the pros/cons of less genericity).

The JoinPoint instance contains static information and RTTI (runtime type information) about the join point we are currently executing over. The StaticJoinPoint instance contains only the static information. The static information (the signature) is retrieved through one of the Signature interfaces by invoking getSignature(). While the RTTI is retrieved through one of the RTTI interfaces by invoking getRtti(), getTarget(), getThis(), getCaller(), getCallee().

The JoinPoint and StaticJoinPointclass have a method called proceed(), this method is used in Around advice to either:

  • Invoke the next advice in the chain.


  • Invoke the target join point (if there are no more advice).
The proceed() method returns the result from the method invocation and in the Around advice you have the option of either returning the value returned from the proceed() method or faking the value and returning something else.

The JoinPoint class has some other interesting methods as well, see the JavaDoc for details.

StaticJoinPoint, JoinPoint, EnclosingStaticJoinPoint

Advice are methods in aspect class. The method signature must conform to some rules, depending on the pointcut where the advice is bound to, when args(..), this(..) and/or target(..) are used to gain access to join point argument / caller / callee instance.

Aside from this pointcut bounded arguments, the advice can have extra arguments of type "JoinPoint" or "StaticJoinPoint", which do not appear in the pointcut. First version of AspectWerkz were supporting only "JoinPoint" as advice argument, and use of "getRtti()" RTTI API was mandatory.

In AspectWerkz 2.x, use of "StaticJoinPoint" and/or "JoinPoint" as advice argument is optional and use of it (or no use of it at all) depends on aspect developer decision. Note that for "around" advice, in order to invoke "proceed()" properly, you will need access to either a "StaticJoinPoint" or "JoinPoint" instance).

When only "StaticJoinPoint" is used, specific optimizations are used to maximize runtime performance since RTTI access is then guaranteed to not happen.

The following demonstrates legal syntax:

@Before("execution(* foo.Bar.method(..))")
void before() {}

@Before("execution(* foo.Bar.method(..))")
void before(StaticJoinPoint sjp) {}

@Before("execution(* foo.Bar.method(..))")
void before(JoinPoint jp) {}

@Around("execution(* foo.Bar.method(..))")
Object around() {
    // possible but rather useless since then all following advices
    // in the chain are skipped since proceed() is not called
    return null;
}

@Around("execution(* foo.Bar.method(..))")
Object around(StaticJoinPoint sjp) throws Throwable {
    return sjp.proceed();
}

@Around("execution(* foo.Bar.method(..))")
Object around(JoinPoint jp) throws Throwable {
    return jp.proceed();
}

@Around("call(* foo.Bar.method(..)) && args(i, j) && target(bar) && this(caller)")
Object aroundCallWithBindings(int i, int j, Bar bar, Object caller, StaticJoinPoint sjp) throws Throwable {
    // no use of RTTI and tedious casting
    // much better performance
    bar.method();
    int localInt = j + i;
    ...
    return sjp.proceed();
}

// use of pointcut composition with argument bindings
@Expression("execution(* foo.Bar.method(..)) && args(i)")
void pointcut_1(int i) {}

@Expression("execution(* foo.Bar.method(..)) && target(bar)")
void pointcut_2(Bar bar) {}

@Around("pointcut_1(myI) && pointcut_2(myBar)")
Object around(JoinPoint jp, int myI, Bar myBar) throws Throwable {
    myBar.method();
    return jp.proceed();
}

                

Since 2.0.RC3, StaticJoinPoint instances (and thus a JoinPoint instances) are exposing the EnclosingStaticJoinPoint instance through the API getEnclosingStaticJoinPoint. It can be usefull especially with call, get, set and handler joinpoints, to capture the enclosing static information ie where the call/get/set/handler occurs.

Signature interfaces

The Signature interfaces are used for retrieving static information about the join point we are currently executing at. The interfaces form a hierarchy in which you can be both fine-grained and course-grained depending on you needs. Just cast to the appropriate interface.

The Signature can be retrieved from the JoinPoint or StaticJoinPoint by invoking the getSignature() method.

The interfaces are:

  • org.codehaus.aspectwerkz.joinpoint.Signature
  • org.codehaus.aspectwerkz.joinpoint.MemberSignature
  • org.codehaus.aspectwerkz.joinpoint.CodeSignature
  • org.codehaus.aspectwerkz.joinpoint.MethodSignature
  • org.codehaus.aspectwerkz.joinpoint.ConstructorSignature
  • org.codehaus.aspectwerkz.joinpoint.FieldSignature
  • org.codehaus.aspectwerkz.joinpoint.CatchClauseSignature
See the JavaDoc for API details.

RTTI interfaces

The Rtti interfaces are used for retrieving RTTI (Runtime Type Information) about the join point we are currently executing at. The interfaces form a hierarchy in which you can be both fine-grained and course-grained depending on you needs. Just cast to the appropriate interface.

The RTTI can be retrieved from the JoinPoint by invoking the getRtti() method.

The interfaces are:

  • org.codehaus.aspectwerkz.joinpoint.Rtti
  • org.codehaus.aspectwerkz.joinpoint.MemberRtti
  • org.codehaus.aspectwerkz.joinpoint.CodeRtti
  • org.codehaus.aspectwerkz.joinpoint.MethodRtti
  • org.codehaus.aspectwerkz.joinpoint.ConstructorRtti
  • org.codehaus.aspectwerkz.joinpoint.FieldRtti
  • org.codehaus.aspectwerkz.joinpoint.CatchClauseRtti
See the JavaDoc for API details.

Using the AspectContext class

The AspectContext class provides methods for getting handles to various parts of the system, that can be used for introspection as well as redefinitions of the runtime system.

To access the AspectContext in a specific aspect you have to define a constructor that takes one org.codehaus.aspectwerkz.AspectContext as its only parameter. The system will then take care of passing in a AspectContext instance when the aspect is instantiated. This instance you can then use as you wish, store it in a member field etc.

This class has many useful methods. For example:

...
AspectContainer getContainer()

void setParameter(String name, String value)
String getParameter(String name)

void setMetaData(Object key, Object value)
Object getMetaData(Object key)

int getDeploymentModel()
...
                

Mixins

We have replaced the old mixin implementation with a completely new and better one. The new implementation mainly gives you two things you did not have before:

  • Serialization of the Mixins -

    The default behaviour is that the mixins will be serialized along with the target class. But you have the option of making the mixins transient (e.g. not serialized with when the target class is serialized), by setting the transient=true flag.


  • Providing your own factory to control the instantiation of the mixin. This means that you can plug in any IoC (dependency injection) framework to handle this for you. The custom factories need only to implement the org.codehaus.aspectwerkz.aspect.MixinFactory interface.

The mixins can be any regular class, which means that it can be a standalone class, an inner class of a regular class or an inner class in your aspect class.

Three different deployment models are supported, perJVM, perClass and perInstance.

  • perJVM - means that there will be one mixin per JVM (like a singleton).
  • perClass - means that there will be one mixin instance per target class.
  • perInstance - means that there will be one mixin instance per target instance.
Note: the perThread deployment model has been left to die in peace. The perJVM deployment model is currently not supported but might come back.

If you are using the default factory implementation you have to either provide a no argument constructor or a constructor that takes the:

  • target class as its only parameter - to be used with the perClass deployment model.
  • target instance as its only parameter - to be used with the perInstance deployment model.
The no argument constructor is mandatory with perJVM.

Annotation definition

To define the mixin using annotations you have to use the org.codehaus.aspectwerkz.annotation.Mixin annotation. If using Java 5 this is an annotation interface (e.g. @interface) else (for JavaDoc annotations) it is a regular interface.

This annotation has three different parameters:

  • expression (can be used as the default anonymous value) - the pointcut expression that is used to pick out the set of classes to apply this mixin to.
  • deploymentModel (optional) - has to me one of perJVM, perClass or perInstance. If not specified then perInstance is used.
  • isTransient (optional) - defines the mixin as transient or not. If not specified then the default is false, e.g. serializable.

Definition using Java 5 annotations

 @Mixin("within(*..domain.*)")
 public class MyMixin { ... }

 @Mixin(
     pointcut="within(*..domain.*)",
     deploymentModel="perClass",
     isTransient=true
 )
 public class MyOtherMixin { ... }
                    

Definition using JavaDoc annotations

 /** @Mixin("within(*..domain.*)") */
 public class MyMixin { ... }

 /**
  * @Mixin(
  *   pointcut="within(*..domain.*)",
  *   deploymentModel="perClass",
  *   isTransient=true
  * )
  */
 public class MyOtherMixin { ... }
                    

XML definition

The XML definition (in the META-INF/aop.xml file) can be used for three different purposes:

  • Only to define which mixins should be used. Similar to how you declare which aspects should be used.) This can be the option if the mixin is defined in annotations. Then you only need to use the class attribute, e.g. <mixin class="foo.bar.MyMixinImpl"/>. See below for details.
  • To completely define the mixin. See below for all the attributes that can be used.
  • To override and/or resolve the definition made using annotations. See below for all the attributes that can be used.

To define the mixin using the XML definition, use the mixin element. It has five different attributes that can be used:

  • class (mandatory) - defines which class to use as the implementation class. Has to be the fully qualified name of the class.
  • deployment-model (optional) - defines the deployment model. Can be one of perJVM, perClass or perInstance.
  • transient (optional) - defines the mixin as transient or not.
  • factory (optional) - defines the custom mixin factory implementation to use with the specific mixin.
  • bind-to (optional) - defines to which class set the mixin should be applied to.

Example:

 <mixin class="foo.bar.MyMixinImpl"/>

 <mixin class="foo.bar.MyOtherMixinImpl"
    deployment-model="perClass"
    transient="true"
    factory="factories.MyMixinFactory"
    bind-to="within(*..domain.*)"/>
                    

Custom Mixin factory

If you need to be in control of how the aspects are instantiated and/or need to pass in additional dependencies or configuration using an IoC (dependency injection) framework or similar. Then you can create custom mixin factory.

The custom factory needs to implement the org.codehaus.aspectwerkz.aspect.MixinFactory:

 public interface MixinFactory {

 /**
  * Creates a new perClass mixin instance, if it already exists then return it.
  *
  * @param the target class
  * @return the mixin instance
  */
 Object mixinOf(Class klass);

 /**
  * Creates a new perInstance mixin instance, if it already exists then return it.
  *
  * @param the target instance
  * @return the mixin instance
  */
 Object mixinOf(Object instance);
 }
                    

The custom mixin factory can only be defined in the mixin element in the META-INF/aop.xml file.

Retrieval of Mixin instances

You can get a hold of the mixin instances for a specific instance or class through the org.codehaus.aspectwerkz.aspect.management.Mixins class.

Example:

// get per class deplolyed mixin
Object perclassMixin = Mixins.mixinOf(MyMixin.class, Target.class);

// get per instance deplolyed mixin
Object perinstanceMixin = Mixins.mixinOf(MyMixin.class, targetInstance);
                    

Retrieval of Aspect instances

You can get a hold of specific aspect instances using the org.codehaus.aspectwerkz.aspect.management.Aspects class.

Example:

// get per jvm deployed aspect
Object singletonAspect = Aspects.aspectOf(MyAspect.class);
               ... = Aspects.aspectOf("uniqueNameOfAspect");

// get per class deployed aspect
Object perclassAspect = Aspects.aspectOf(MyAspect.class, Target.class);
              ... = Aspects.aspectOf("uniqueNameOfAspect", Target.class);

// get per instance deployed aspect
Object perinstanceAspect = Aspects.aspectOf(MyAspect.class, targetInstance);
                 ... = Aspects.aspectOf("uniqueNameOfAspect", targetInstance);
                

Example of an Aspect

This is a simple example showing how an aspect implementation with a couple of advice and an introduction could look like (Note: annotations to define the aspects are ommitted here):

public class MyAspect {

     public Object myAroundAdvice(StaticJoinPoint staticJoinPoint) throws Throwable {
         // do some stuff
         Object result = staticJoinPoint.proceed();
         // do some other stuff
         return result;
     }

     public void myBeforeAdvice(JoinPoint joinPoint) {
         // do some stuff
     }

     // the Mixin could be an outer class
     public static class MyIntroduction extends SuperMixin implements ContractualInterface {
         ... // introduced methods and fields
     }
}
                    

Choosing a definition model

The XML definition allows to define the pointcut expressions in an external file. It can be used to provide aspects that needs to be tuned without an extra development phase (apart from editing an XML file). The main disadvantage with this approach is that the implementation is separated from the definition which makes the code harder to refactor, maintain and reuse.

Using the XML definition is a bit more difficult as well when pointcuts have complex signature to expose runtime arguments and instances (args(..), this(..), target(..)).

The Annotation definition allows you to have truly self-contained aspect components. Those are easier to maintain, refactor and reuse as well as build libraries upon. The drawbacks are when you are not using Java 5, it requires an additional post-compilation step to annotate them with the metadata. Moreover it introduces tighter coupling, and makes the aspect harder to configure. You would have to extend the aspect to refine it.

We have exprerienced that a combination of both definition formats can be beneficial. For example define the reusable aspects and advice using annotations but do the pointcut definition in the external XML file. This allows you to make certain decisions later in the development cycle, for example at deployment time instead of at compile time.