XML definition

What is important to understand is that both the Annotation and the XML definition are just different views of the same underlying model. This means that they can easily co-exist and can succesfully be used together. The XML definition can be used as a replacement to the Annotation definition or as a complement. It can be used to refine and override definitions made in annotations as well as resolve missing pieces (for example pointcut definitions referenced but not defined) in the annotation definition. See the Choosing a definition model section for best practices.

Aspects

An aspect is defined in XML using the aspect element, which has the following attributes:

  • class - [mandatory] specifies a fully qualified class name for the aspect implementation class.


  • deployment-model - specifies the deployment model for the aspect. The default is perJVM if not specified
    • perJVM - deploys the aspect as perJVM.
    • perClass - deploys the aspect as perClass.
    • perInstance - deploys the aspect as perInstance.


  • name - optional unique name of the aspect in the system. It will default to the fully qualified class name of the aspect.

Inside the aspect elements you then define the poincuts and advice.

Pointcuts

The pointcut is the construct that picks out join points, i.e. selects sets of well-defined points in the program flow. In the XML definition pointcuts are defined using the pointcut element.

When defining a pointcut there are two attributes that need to be specified:

  • name - [mandatory] specifies the name of the pointcut. Needs to be composed of a first part also called pointcut name, unique throughout the aspect defininition, and an optional second part called the pointcut signature : name="<pointcut name>[(<pointcut signature>)]". The signature must name its parameters (as if it was some source code).

    Caution: pointcut names must be valid Java identifiers (only consist of these characters: [A-Z], [a-z], [0-9] and the characters $ and _; not for example - or /).

    The optional pointcut signature must be compatible with the args(), this() and target() pointcuts designators when used. The abbreviations for java.lang.* can be used as described here.
  • expression - [mandatory unless body is used] specifies the expression for the pointcut. This is the pattern that picks out the join points that should be included in the pointcut. This attribute is "optional". If not specified, the <pointcut> element must have the expression in its body.

    See the Join point selection pattern language section for a detailed description on how these patterns are written and see the Pointcut definition and Pointcut composition sections for details on how pointcuts are defined and composed.



Example of some pointcut definitions:

<aspect ...>
    <pointcut name="pc1" expression="execution(* foo.Bar.method(..))"/>
    <pointcut name="pc2" expression="set(* foo.Bar.m_field)"/>
    <pointcut name="pc3" expression="get(* foo.Bar.m_field)"/>
    <pointcut name="pc4" expression="handler(java.lang.Exception)AND withincode(foo.bar.*.new(..))"/>
    <pointcut name="pc5" expression="call(String foo.Callee.method()) AND within(foo.bar.*)"/>
    <pointcut name="pc6" expression="cflow(execution(* Transaction.begin(..)))"/>
    ...
    <!-- do not use a pointcut name more than once (pcArg1) -->
    <pointcut name="pcArg1(String s)" expression="execution(* foo.Bar.method(..)) AND args(s, ..)"/>
    <pointcut name="pcArg1Same(String s)" expression="pc1 AND args(s, ..)"/>
    <pointcut name="pcArg1Other(com.Foo foo, String[] s)" expression="execution(* foo.Bar.method(..)) AND args(foo, int, .., s)"/>

    <!-- use element body instead -->
    <pointcut name="pcMultiLine">
        execution(int com.Do.foo(..))
        OR execution(int come.Done.bar(..))
    </pointcut>
</aspect>
                

System wide pointcuts

The pointcuts can also be "system-wide", which means that you can define pointcuts outside the aspects, within the system tags. These can then be used by all aspects in the system defintion.

Deployment Scope

The deployment-scope element within the aspect can be used to define and name a pointcut that will be later used to hotdeploy and undeploy Aspects. The attributes and their meaning is the same as for the pointcut elements.

  • name - the name of the deployment scope
  • expression - the pointcut expression
See the specific hotdeployment section.

System wide deployment Scope

The deployment-scope element within the system can be used to define and name a pointcut that will be later used to hotdeploy and undeploy Aspects. The attributes and their meaning is the same as for the pointcut elements.

  • name - the name of the deployment scope
  • expression - the pointcut expression
See the specific hotdeployment section.

Advice

In the XML definition advice are defined using the advice element.

When defining the advice there are three attributes that need to be specified:

  • name - [mandatory] the name of the advice is the name of the method in the aspect class that implements the advice, with an optional method signature if pointcut with signature are used. Abbreviations can be used in this signature, including for the JoinPoint or StaticJoinPointparameter. The signature must name its parameters (as if it was some source code) like advice3(JoinPoint jp, int i). The method defined this way must exist with the same signature in the aspect class hierarchy.


  • type - the type defines the type of the advice. Valid types are:
    • around - defines an around advice
    • before - defines an before advice
    • after - defines an after (finally) advice
    • after finally - defines an after finally advice
    • after returning - defines an after returning advice
    • after throwing - defines an after throwing advice
    • after returning(..) - defines an after returning advice and filters out or bind the returned value
    • after throwing(..) - defines an after throwing advice and filters out or bind the throwned exception


  • bind-to - binds the advice to a pointcut by referencing the name of the pointcut or by defining an anonymous pointcut. If the pointcut has a signature (with args(), this() and/or target() or after returning(..), after throwing(..)), then those must be refered as named in the advice name signature part.


For after returning and after throwing, you can filter out based on the returned value / exception thrown or use explicit binding.

after returning [TYPE] advice is 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.

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

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

after throwing [TYPE] advice is executed if the returns with an exception and the actual type of the exception that is 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 returns with an exception.

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

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

Example:

<advice name="advice1"
        type="before"
        bind-to="(pc1 || pc2) AND pc3"/>

<advice name="advice2"
        type="around"
        bind-to="execution(int examples.caching.Pi.getPiDecimal(int))"/>

<advice name="advice3(JoinPoint jp, int i)"
        type="around"
        bind-to="pc1 AND args(i, String[], foo.Bar)"/>

<advice name="advice4(org.codehaus.aspectwerkz.joinpoint.JoinPoint jp, int i)"
        type="around"
        bind-to="execution(int examples.caching.Pi.getPiDecimal(..)) AND args(i)"/>
                 

Passing parameters to aspects

You 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>
                

From within an Aspect subclass use the API AspectContext.getParameter("timeout") to retrieve the parameter value as a String.

Introductions

Interface only introductions

Interface only introductions are defined within the aspect element using an introduce elemement. When defining the interface only introduction the following attributes can be used:

  • class - [mandatory] the class name of the introduced interface


  • bind-to - [mandatory] binds the introduction to a class using the within(...), hasmethod(...) and/or hasfield(...) pointcuts


The introduce element supports nested bind-to elements.

 <aspect ...>
	  ...
	  <introduce class="java.io.Serializable" bind-to="within(test.some.ToBeSerializable)"/>
	  ...
 </aspect>
                    

Mixins

Mixin allows to introduce both interface(s) and implementation(s) of it. The mixin element within the system element is then used to declare the mixin. The mixin itself can be Annotation defined or XML defined.

The mixin element in 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 ad 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 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 (defaults).
  • 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, using the within(...), hasmethod(...) and/or hasfield(...) pointcuts.

Example:

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

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

Package namespaces

Package namespaces provide a way to simplify the creation/modification of the XML definition file so that it is not necessary to prefix all class with the complete package information.

You have two ways of defining a package namespace:

  • using the base-package attribute in the system element. This defines a global package namespace for all elements defined within the system element.


  • using the package element. This element has one attribute; name, which defines the package namespace.
The package name will be used as a prefix for all nested elements.

Example

<aspectwerkz>
    <system id="foodemo" base-package="foo">
        <!-- All classes are prefixed by 'foo' -->

        <package name="bar">
            <!-- All classes within these 'package' tags are prefixed by 'foo.bar' -->
        </package>

        <package name="baz.buzz">
            <!-- All classes within these 'package' tags are prefixed by 'foo.baz.buzz' -->
        </package>
    </system>
</aspectwerkz>
                

Transformation scopes

Using transformation scopes you can choose to perform the transformation within certain packages only. E.g. filter out all classes from all other packages in the transformation process. This can speed up the transformation process a lot as well as assures you that only classes within the packages you have defined are getting transformed no matter how freely you have defined your pointcut patterns.

A transformation scope is defined using the exclude and include element which have one attribute package where you define the package name. You can define as many transformation scopes as you want.

The package attribute supports only .* as an ending pattern (package and all sub package).

During the transformation process (online or offline), a class might be transformed (depending on the pointcuts) if

  1. the class does not belong to any exclude packages if any
  2. and
  3. the class belongs to at least one include packages if any
Note that when include is used the selection is much more restrictive. This selection mechanism should be used as most as possible especially in online mode since it enables an early filtering.

Example

<aspectwerkz>
    <system id="sample">
        <!--
            Transformations will only take place within the 'org.codehaus.package' package and its subpackages
        -->
        <include package="org.codehaus"/>
        <include package="org.codehaus.*"/> <!-- synonymous of org.codehaus -->
        <exclude package="com.oracle.*"/>
        ...
    </system>
</aspectwerkz>
                

DTD for XML definition

Each distribution comes with a bundled DTD so that it is not looked for on the web at runtime. The XML is not validated against its DTD at runtime so be cautious to provide a valid XML defintion.

When you write your XML definition file, add the following at the top of your XML to reference the latest release:

<!DOCTYPE aspectwerkz PUBLIC
    "-//AspectWerkz//DTD//EN"
    "http://aspectwerkz.codehaus.org/dtd/aspectwerkz2.dtd">
            

It is possible to specify a specific released version number as well (starting with 0.8)

<!DOCTYPE aspectwerkz PUBLIC
    "-//AspectWerkz//DTD 2.0//EN"
    "http://aspectwerkz.codehaus.org/dtd/aspectwerkz_2_0.dtd">
                
and for 1.x
<!DOCTYPE aspectwerkz PUBLIC
    "-//AspectWerkz//DTD 1.0//EN"
    "http://aspectwerkz.codehaus.org/dtd/aspectwerkz_1_0.dtd">
                

Example of an XML definition

Here is an example where all the definitions are put together into a single AspectWerkz XML definition file.

<aspectwerkz>
    <system id="sample">

        <pointcut name="systemWide" expression="execution(int com.Do.foo(..))"/>

        <pointcut name="mutliLine">
            call(int com.Do.foo(..))
            AND within(com.ToDO)
        </pointcut>

        <deployment-scope name="mutliLineScope">
            within(com.DynamicAOP)
        </deployment-scope>

        <!-- package prefix "examples." will be used for class=".." 
             attributes of <aspect> and <mixin> elements -->
        <package name="examples">

            <aspect class="caching.CachingAspect" deployment-model="perInstance">
                <param name="timeout" value="10"/>

                <introduce class="IntroductionTestAspect$MarkerInterface"
                           bind-to="within(test.mixin.perinstance.ToBeIntroduced)"/>

                <pointcut name="callee"
                          expression="execution(int examples.caching.Pi.getPiDecimal(int))"/>

                <pointcut name="caller"
                          expression="call(int examples.caching.Pi.getPiDecimal(int)) && within(examples.caching.*)"/>

                <advice name="invocationCounter"
                        type="before"
                        bind-to="caller"/>

                <advice name="cache"
                        type="around"
                        bind-to="callee"/>

                <!-- use of args() -->
                <pointcut name="calleeArgFiltered(int i)"
                          expression="callee AND args(i)"/>

                <advice name="traceArg(JoinPoint jp, int theArg)"
                        type="around"
                        bind-to="calleeArgFiltered(theArg)"/>

            </aspect>

            <mixin
                class="caching.MyMixin"
                deployment-model="perClass"
                bind-to="within(test.mixin.perinstance.ToBeAffectedByMixin)"/>

            <!-- annotation defined mixin -->
            <mixin
                class="caching.MyMixinAnnotationDefined"/>

        </package>
    </system>
</aspectwerkz>