AspectWerkz supports two models for Aspect components.
The model 1 is the historical ones. Aspects are defined in an XML file as an arrangement of java classes which are the Advices and the Introductions implementations and interfaces. The Pointcuts are defined in the XML file thru a specific syntax. The binding between pointcuts and Advices and/or Introductions defines on which class of the application to apply concern brought by the Advice and Introduction implementations.
The model 2 is based on MetaData (JSR-175). Aspect are pure java classes containing Advices as methods, Introductions as inner-class, and Pointcuts as field. Doclet in the Aspect class source file defines the binding between a Pointcut and Advices and/or Introductions. The Aspect class needs a post-compilation phase to incorporate the doclets in the aspect class file bytecode (this won't be needed with java 1.5). The XML is only declaring the Aspect classes.
To understand which model to use read the next section.
The following sections detail the Model 1 XML centric approach where Advices and Introductions are classes and Aspect are described in an XML file.
The Advice
class implements the advice concept,
i.e. defines code that is executed when a join point is reached.
There are currently four types of Advices supported:
AroundAdvice
- is invoked "around" the
join point. Can be used to intercept method
invocations.
PreAdvice
- is invoked before the join
point. Can be used for advising fields or caller side
pointcuts.
PostAdvice
- is invoked after the join
point. Can be used for advising fields or caller side
pointcuts.
ThrowsAdvice
- advises join points
where an exception is thrown out of a method.
AroundAdvice
An AroundAdvice
is implemented by extending
the AroundAdvice
class and implementing the
abstract method Object execute(final JoinPoint jp)
.
Please note: An AroundAdvice
can not be used
with caller side or field pointcuts.
Here is a simple example of an AroundAdvice
.
(For more examples see the
Examples section.)
It is in the method execute
that the action
takes place. The JoinPoint
object that is
passed to the method contains metadata of the current
join point. To invoke the next advice in the chain (or the
target method if there are no more advices) simply call
joinPoint.proceed()
. This method will return
the result from the next advice (or the target method).
public class MyAroundAdvice extends AroundAdvice { public MyAroundAdvice() { super(); } public Object execute(final JoinPoint joinPoint) throws Throwable { // do some stuff Object result = joinPoint.proceed(); // do some more stuff return result; } }
PreAdvice
A PreAdvice
is implemented by extending either
the abstract PreAdvice
class and implementing
the abstract method void execute(final JoinPoint jp)
.
The PreAdvice
class is being executed before
the join point (that it has been applied to) has been is reached.
Here is a simple example of a PreAdvice
advice.
It is in the method execute
that you can implement
your logic. The JoinPoint
object that is
passed to the method contains metadata for the current
join point. There is no need to call joinPoint.proceed()
for either PreAdvices
or PostAdvices
.
public class MyPreAdvice extends PreAdvice { public MyPreAdvice() { super(); } public void execute(final JoinPoint joinPoint) throws Throwable { // do some stuff } }
PostAdvice
A PostAdvice
is implemented by extending either
the abstract PostAdvice
class and implementing
the abstract method void execute(final JoinPoint jp)
.
The PreAdvice
class is being executed before
the join point (that it has been applied to) has been is reached.
Here is a simple example of a PostAdvice
advice.
It is in the method execute
that you can implement
your logic. The JoinPoint
object that is
passed to the method contains metadata for the current
join point. There is no need to call joinPoint.proceed()
for either PreAdvices
or PostAdvices
.
public class MyPostAdvice extends PostAdvice { public MyPostAdvice() { super(); } public void execute(final JoinPoint joinPoint) throws Throwable { // do some stuff } }
ThrowsAdvice
A ThrowsAdvice
is implemented by extending the
the ThrowsAdvice
class and implementing the abstract
method void execute(final JoinPoint jp)
.
The ThrowsAdvice
class is being executed
after the join point (that it has been applied to) has been
reached. I.e. when a specific exception has been thrown out
of a specific method.
Here is a simple example of a ThrowsAdvice
advice.
It is in the method execute
that you can implement
your logic. The JoinPoint
object that is passed to
the method contains metadata of the current join point.
public class MyThrowsAdvice extends ThrowsAdvice { public MyThrowsAdvice() { super(); } public void execute(final JoinPoint joinPoint) throws Throwable { Throwable cause = ((ThrowsJoinPoint)joinPoint).getException()); // do some stuff } }
Attributes
When defining the advices there are three attributes that needs to be specified:
name
-
for each advice you first have define the name of the
advice. This name has to be unique and will work as a handle
to the advice to be used when referencing the advice in the
system.
advice
-
secondly you have to define the class name of the advice
that the name attribute should be mapped to.
deployment-model
-
last we have an optional attribute specifying the deployment
model to use. If no deployment model is defined the default
perJVM (singleton) will be used.
(For more information about the deployment model
types available see the
Deployment models section).
Here you also have the possibility to pass parameters to the advices. See the Passing parameters to advices section for a detailed description.
XML definition
<advice-def name="advices/caching" class="advices.CachingAdvice" deployment-model="perInstance"> <param name="timeout" value="10"/> </advice>
The Introduction
class implements the concept of
Mixins/Open Classes. I.e. an Introduction
makes it
possible to extend a class with a new interface and/or a new
implementation (methods and fields).
Both the interface and the implementation extensions are just regular Java interfaces and classes. There is no need to have them implement a specific interface or extend a certain class. All you have to do is define them. The only rules are that the introduced implementation has to implement the introduced interface and have a default no-argument constructor.
When defining an interface introduction you only have to specify the interface, but when introducing a new implementation to a class, you must specifiy both the implementation class a matching interface. This is needed since if you don't specify an interface that the client can cast the target object to, the introduced implementation will not be accessible.
Note: if you add more than one Introduction
to
a target class then you have to make shure that the
names of the methods does not collide (or you will get
strange results).
Attributes
When defining the introductions there are four attributes that needs to be specified:
name
-
each introduction needs to have a unique name that will work
as a handle to the advice to be used when referencing the
introduction in the system.
interface
-
this attribute specifies the full name of the interface class
to use.
implementation
-
this attribute specifies the full name of the implementation
class to use. (Is skipped when we are defining an interface
introduction).
deployment-model
-
is an optional attribute specifying the deployment model
to use. If no deployment model is defined the default perJVM
(singleton) will be used. (For more information about
the deployment model types available see the
Deployment models section).
XML definition
<introduction-def name="java/io/Serializable" interface="java.io.Serializable"/> <introduction-def name="mixins/Mixin" interface="mixins.Mixin" implementation="mixins.MixinImpl" deployment-model="perThread"/>
(These examples only shows how to define the
Introduction
, for examples how to add them see
the Aspects section.)
The Pointcut
class implements the pointcut concept.
Pointcuts selects join points and values at those points,
i.e. selects well-defined points in the program flow.
There are currently four different types of pointcuts supported:
MethodPointcut
- picks out join points
defining method execution.
Valid advice for this pointcut is AroundAdvice
.
FieldPointcut
- picks out join points
defining field access or modification.
Valid advices for this pointcut are PreAdvice
and PostAdvice
.
ThrowsPointcut
- picks out join points
definining where an exception is thrown out of a method.
Valid advice for this pointcut is ThrowsAdvice
.
CallerSidePointcut
- picks out join points
defining method invocation on the caller side.
Valid advices for this pointcut are PreAdvice
and PostAdvice
.
CFlowPointcut
- picks out join points
defining a control flow (cflow). This pointcut can only
be used on conjunction with other pointcuts.
Attributes
When defining the pointcuts there are three attributes that needs to be specified:
name
-
specifies the name of the pointcut. Needs to be a unique
name throughout the aspect definintion.
Caution: names must only consist of these characters:
[A-Z]
, [a-z]
, [0-9]
and the characters $
and _
(not for example -
or /
).
type
-
specifies the type of the pointcut.
Valid types are (all lowercase is also valid):
method
setField
getField
throws
callerSide
cflow
pattern
-
specifies the pattern for the pointcut. This is the
pattern that picks out the join points that should be
included in the pointcut.
For the ThrowsPointcut
the pattern is defined like this:
methodPattern#fullyQualifiedNameOfException
.
For the CallerSidePointcut
the pattern is defined like this:
callerSideClassPattern->calleeSideMethodPattern
.
See the
Join point selection pattern language
section for a detailed description on how these
patterns work and are used.
` XML definition
<aspect ...> <pointcut-def name="pc1" type="method" pattern="* foo.Bar.method(..)"/> <pointcut-def name="pc2" type="setField" pattern="* foo.Bar.m_field"/> <pointcut-def name="pc3" type="getField" pattern="* foo.Bar.m_field"/> <pointcut-def name="pc4" type="throws" pattern="* foo.Bar.method(..)#java.lang.Exception"/> <pointcut-def name="pc5" type="callerSide" pattern="foo.Caller->String foo.Callee.method()"/> <pointcut-def name="pc6" type="cflow" pattern="* Transaction.begin(..)"/> ... </aspect>
The Aspect
class implements the aspect concept.
Aspects are AspectWerkz's
unit of modularity for
crosscutting concerns. They are defined in terms of pointcuts,
advices and introductions.
Abstract aspects - aspect inheritance
You have the possibility of defining abstract aspects that you
can reuse by letting aspects inherit the the abstract aspect using
the extends
attribute. Aspect inheritance works
pretty much like regular class inheritance. An abstract aspect
is defined using the abstract-aspect
element.
Attributes
When defining the aspects there is first one attribute that needs to be specified:
name
- specifies a unique name for the aspect.
extends
- specifies the abstract aspect that
the aspect extends (optional).
Adding the pointcuts definitions
In the aspect definition you put the pointcut definitions (see the Pointcuts section).
Adding the introductions
Then you specify the introductions that you want to define in this
aspect
. This is done using the bind-introduction
element. You can also use the introduction
element although
it is deprecated and therefore not recommended.
This element has an attribute class
where you define
the pattern for the classes that you want to be applied by this/these
introductions. Within this element you define the references to the introductions.
Using the introduction-ref
element:
<introduction-ref name="nameOfIntroduction"/>
Adding the advices
You also define which advices should be applied to which pointcuts.
This is done using the bind-advice
element. You can also use the
advice
element although it is deprecated and therefore not recommended.
The advice
element has an attribute called expression
(pointcut
works fine as well) in which you can define an expression
based on the names of the pointcuts you have defined for this aspect.
This expression can be any (almost) kind of algebraic expression.
The only difference is that you have to use OR
instead
of ||
and AND
instead of &&
(lowercase works fine as well). AND is needed because it is cumbersome
to write && in XML (needs to be escaped) and OR is used to make
it coherent;
Here you also define if the pointcut/expression should be a part of a
control flow using the cflow
attribute. The cflow
is defined using its pointcut name.
XML definition
<abstract-aspect name="MyAbstractAspect"> <bind-advice cflow="facadeCalls" pointcut="setters AND !getters"> <advices-ref name="log_and_cache"/> </bind-advice> <bind-advice pointcut="persistentFields"> <advice-ref name="persistent"/> </bind-advice> </aspect> <aspect name="MyAspect" extends="MyAbstractAspect"> <bind-introduction class="domain.*"> <introduction-ref name="serializable"/> <introduction-ref name="mixin"/> </bind-introduction> <pointcut-def name="facadeCalls" type="cflow" pattern="* *..facade.*.*(..)"/> <pointcut-def name="setters" type="method" pattern="String domain.*.set*(..)"/> <pointcut-def name="getters" type="method" pattern="String domain.*.get*(..)"/> <pointcut-def name="persistentFields" type="setField" pattern="* domain.*.*"> </aspect>
The JoinPoint
class implements the join point
concept, i.e. a well-defined point in the program flow.
A JoinPoint
is picked out by a Pointcut
.
There are four different types of join points:
MethodJoinPoint
FieldJoinPoint
ThrowsJoinPoint
CallerSideJoinPoint
You only have to deal with the different types of
join points when you in your Advice
need to
cast the JoinPoint
object to a specific type
to be able to retrieve meta-data from this specific join point.
See the JavaDoc for more information on what information is
available.
The following sections outlines the Model 2 - Self-defined Aspects approach, where Aspects are classes whose
methods are Advices, fields are Pointcuts and inner classes are Introductions with metadata markers (JSR-175 ready).
You should be familiar with the vocabulary of AOP and the AspectWerkz implementation as explained
in the model 1 section.
The Aspect class implements the aspect concept. Aspects are AspectWerkz's unit of modularity for crosscutting concerns. They are defined in terms of pointcuts, advices and introductions.
Aspect
Aspect are regular java classes. They must satisfy two criterias:
org.codehaus.aspectwerkz.attribdef.aspect.Aspect
whether
directly or indirectly by extending another subclass.
@Aspect
metadata marker at the class level i.e. in the class javadoc section.
Here is also where you specify the deployment model of the Aspect.
Aspect
in its object hierarchy. The Aspect
class provides some useful operations to access runtime information:
___AW_getTargetClass()
to access the target class
Abstract aspects - aspect inheritance
Since the Aspects are pure java classes in this model, 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.
Metadata
When defining the aspect, the deployment model is specified as metadata argument of the metadata tag @Aspect
.
The current implementation uses a doclet syntax. AspectWerkz will support JSR-175 syntax as well, as soon as it is available.
@Aspect
class level metadata has
name=
named parameter which specify the name of the aspect.
The default is the aspect class name if not specified.@Aspect perJVM
- deploys as perJVM. This is the default if only @Aspect
is specified.
@Aspect perClass
- deploys as perClass.
@Aspect perInstance
- deploys as perInstance.
@Aspect perThread
- deploys as perThread.
Adding the pointcuts definitions
In the aspect class you put the pointcut definitions as fields of the type org.codehaus.aspectwerkz.attribdef.Pointcut
along with metadata attributes which specifies the type of pointcut (execution, call, set, get, cflow or throws).
See Pointcuts section.
In the aspect class you specify the introduction to add as field for pure interface introduction (marker interface with no required method) or as public inner-class for interface and implementation introduction.
Pure interface introduction are added by adding a field to the aspect. The field type has to be the
interface that you want to introduce. The @Introduce
metadata is then used to specify
the pattern matching the classes you want the introduction to be applied to.
See Introductions section.
Interface introduction with implementation, also known as mixins, are added by adding a public inner-class to the aspect class.
The inner-class is then the default introduction/mixin implementation. It can extend any class you want, just like any other regular java class.
The @Implements
metadata specifies the pattern matching the classes you want the introduction/mixin to be applied to.
The interface(s) introduced can be whether be set explicitly by letting the inner-class implement the interface(s), whether implicitly
by inheriting another class which is itself implementing the interface(s).
This can be handy when distributing reusable aspects.
See Introductions section.
Adding the advices
In the aspect class the advices are regular methods conforming to the public Object <name of method>(JoinPoint joinPoint) throws Throwable
signature.
The type of the advice, either Around
, Before
or After
, is specified
using metadata for the method along with the method or field pattern or pattern expression to which it the advice should be bound.
See Advices section
This expression can be any (almost) kind of algebraic expression.
The operators ||
, OR
, &&
, AND
are supported.
Here you also define if the pointcut/expression should be a part of a
control flow using an algebraic AND
expression mixing one or more
pointcut names with one or more poincut names of type CFlow
i.e. whose matching Pointcut
fields are marked with @CFlow
metadata.
XML definition
The XML definition is just declaring which concrete aspects to use. See dedicated section for complete definition issue documentation.
<use-aspect class="package.NonAbstractAspect"/>
Source sample
The following source sample gives the main ideas of the self-defined Aspect. Please remember that the metadata markers are inserted in the bytecode through a post-compilation step which won't be needed under java 1.5.
/** * @Aspect perInstance name=SomeNameForMyAspect */ public class MyAspect extends Aspect { /** * @Implements com.mypackage.* */ MarkerInterface anIntroduction; /** * @Execution * com.mypackage.Target.*(..) */ Pointcut pc1; /** * @Around pc1 */ public Object advice1(final JoinPoint joinPoint) throws Throwable { // do some stuff Object result = joinPoint.proceed(); // do some other stuff return result; } /** * @Introduce com.mypackage.* */ public class OtherIntroduction extends SuperMixin implements ContractualInterface { ... // introduced methods and fields } }
The Pointcut
class implements the pointcut concept.
A Pointcut picks out join points, i.e. selects well-defined points in the program flow.
The Pointcuts are implemented as fields in the Aspect class and they have to follow the following requirements:
org.codehaus.aspectwerkz.attribdef.Pointcut
and should be
declared in the aspect class or hierarchy.
The name of the pointcut is the field name.
The following types of pointcuts are currently supported and type is specified as metadata at the field level:@Execution <methodPattern>
- picks out join points defining method execution.
Valid advice method metadata for this pointcut is @Around
@Call <callerSidePattern>
- picks out join points defining method invocation
on the caller side.
Valid advice method metadata for this pointcut are @Before
and @After
.
@Class <classPattern>
- picks out class names.
To be used with mixin @Implements
and @Introduce
metadata.
@Set <fieldPattern>
- picks out join points
defining field modification.
Valid advice method metadata for this pointcut are @Before
and @After
.
@Get <fieldPattern>
- picks out join points
defining field access.
Valid advice method metadata for this pointcut are @Before
and @After
.
@Throws <throwsPattern>
- picks out join points
definining where an exception is thrown out of a method.
Valid advice method metadata for this pointcut is @Around
.
@CFlow <methodPattern>
- picks out join points
defining a control flow (cflow). This pointcut can only be used on conjunction with other
pointcut types in an algebraic AND
expression.
/** * @Execution * com.package..*.*(..) */ Poincut allMethods; /** * @Set * com.package.Constants.* */ Pointcut allConstantAccess;
These metadata attributes are followed by the pattern. The exact syntax depends of the type of the Advice itself. This is the pattern that picks out the join points that should be included in the pointcut.
For the@Throws
the pattern is defined like this:
methodPattern#fullyQualifiedNameOfException
.
For the @Call
the pattern is defined like this:
callerSideClassPattern->calleeSideMethodPattern
.
See the
Join point selection pattern language
section for a detailed description on how these patterns work and are used.
The Advices are implemented as regular methods in the Aspect class with the following requirements:
public Object <name of method>(JoinPoint joinPoint) throws Throwable
(the public modifier is not mandatory, choose according to your needs).
The supported types of Advices are the following. Each type is a metadata marker at the method level with:
name=
parameter which specify the advice name.
Defaults to the <aspect class name>.<method name> if not specified.
@Around <expression>
- is invoked "around" the
join point. Can be used to intercept method invocations on the 'callee' side.
@Before <expression>
- is invoked before the join
point. Can be used for advising fields or method invocations on the 'caller' side.
@After <expression>
- is invoked after the join
point. Can be used for advising fields or method invocations on the 'caller' side.
@Throws <expression>
- advises join points
where an exception is thrown out of a method.
Here is a simple example of an AroundAdvice.
(For more examples see the Examples section.)
It is in the method execute
that the action
takes place. The JoinPoint
object that is
passed to the method contains metadata of the current
join point. To invoke the next advice in the chain (or the
target method if there are no more advices) simply call
joinPoint.proceed()
. This method will return
the result from the next advice (or the target method).
It is possible to cast the JoinPoint to the JointPoint subclass matching
the advice type used (MethodJoinPoint
, FieldJoinPoint
, ThrowsJoinPoint
and subclasses).
/** * Non anonymous expression (pc1 and pc2 are fields of type Pointcut with metadata). * @Around pc1 && pc2 */ public Object myAroundAdvice(JoinPoint joinPoint) throws Throwable { // do some stuff Object result = joinPoint.proceed(); // do some more stuff return result; } /** * Anonymous pointcut. * @Around * com.package.Target.*(..) */ public Object myAroundAdvice(JoinPoint joinPoint) throws Throwable { // do some stuff Object result = joinPoint.proceed(); // do some more stuff return result; } }
The Introduction class implements the concept of Mixins or Open Classes. I.e. an Introduction makes it possible to extend a class with a new interface and/or a new implementation (methods and fields).
In model 2, introductions are defined as
@Implements <classPattern>
.
@Introduce <classPattern>
.
Interface introductions (introduction of marker interfaces) are defined as fields in the aspect class.
The type of the field is the interface to introduce.
The field is marked with metadata @Implements <classPattern>
to specify to which
classes the introduction applies.
The name of the introduction is the field name.
When using abstract aspects or aspect inheritance, the aspect's super class can define interface
introductions without specifying a @Implements <classPattern>
metadata.
The concrete aspect should thus override the fields and specify the metadata defining to which
classes the introduction applies.
/** * @Aspect */ public MyAspect extends Aspect { /** * @Implements com.package.* */ protected Serializable introduction1; /** * @Implements com.package.* */ public OtherMarkerInterface introduction2; }
Implementation introductions (interface with concrete implementation), also known as mixins, are defined
as public inner class of the aspect class.
It is mandatory for the inner class to be accessible with a no-arg constructor, thus to be public or
to explicitly have a no-arg constructor.
The inner class implements the interface(s) to introduce on the target class.
The inner class is marked with metadata @Introduce <classPattern>
to specify to which
classes the introduction applies.
The @Introduce
attribute accepts an optional deploymentModel=
parameter to specify the
introduction deployment model. If not specified the aspect deployment model applies.
See deployment model section.
The name of the introduction is the fully qualified inner class name e.g.
<aspectClassName>$<innerClassName>
.
When using abstract aspects or aspect inheritance, the aspect's super class can define introductions without
specifying a @Introduce <classPattern>
metadata.
The concrete aspect should thus declare an inner class that extends the super class aspect one's and
specify thru metadata to which classes the introduction applies.
/** * @Aspect */ public MyAspect extends Aspect { /** * Anonymous pointcut. * * @Introduce com.package.* */ public class MyIntroduction extends SuperIntroduction implements ToBeIntroduced { // introduced methods implementation ... } /** * @Class com.package.Foo */ Pointcut pc1; /** * Named pointcut(s) in expression. * * @Introduce pc1 */ public class AnotherIntroduction implements AnotherToBeIntroduced { // introduced methods implementation ... } }
It is possible to replace the introduction implementation at runtime using a call like
SystemLoader.getSystem("systemId").getMixin("test.attribdef.aspect.IntroductionTestAspect$MyImpl"). ___AW_swapImplementation("test.attribdef.aspect.IntroductionTestAspectMyImplReplacement");
The swapped implementation must implement the introduced interfaces, but can be an autonomous class or an aspect inner class. Only the default introduced implementation must be an inner class.
This section references all metadata used in the model 2 - Self defined aspect model.
meta | level | component | anonymous parameter | parameter(s) |
---|---|---|---|---|
[O:defaultValue] for optional parameter with default value | ||||
@Aspect | class | Aspect | perJVM | perClass | perInstance | perThread [O:perJVM] | name [0:<aspectClassName>] |
@Implements | field | Interface Introduction | <classPattern> | |
@Introduce | inner class, class level | Implementation Introduction | <classPattern> | deploymentModel=perJVM | perClass | perInstance | perThread [O: aspect'one] |
@Class | Pointcut field | Pointcut, class selection | <classPattern> | |
@Execution | Pointcut field | Pointcut, method execution | <methodPattern> | |
@Call | Pointcut field | Pointcut, method call | <callerSidePattern> | |
@Set / @Get | Pointcut field | Pointcut, field modification / access | <fieldPattern> | |
@Throws | Pointcut field | Pointcut, exception throwned out | <throwsPattern> | |
@CFlow | Pointcut field | Pointcut, in cflow of | <methodPattern> | |
@Around | Method | Advice for @Around, @Throws | <expression> | name [0:<aspectClassName>.<methodName> |
@Before | Method | Advice for @Call, @Set, @Get | <expression> | name [0:<aspectClassName>.<methodName> |
@After | Method | Advice for @Call, @Set, @Get | <expression> | name [0:<aspectClassName>.<methodName> |
@Throws | Method | Advice for @Throws | <expression> | name [0:<aspectClassName>.<methodName> |
@Attribute.<name> | any | custom runtime accessible attribute |
The model 2 - self-defined Aspects have to be post-compiled to incorporate the metadata into the class file bytecode.
This post-compilation step will not be needed with java 1.5 and JSR-175. For now you need to first compile
the aspect classes with javac compiler and then post compile the .class
files with the aspect
source code as input.
See specific part
The model 1 - XML centric model 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). This model leads to a more exploded aspect since several classes are needed (one per Advice). 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.
The model 2 - Self-defined aspect allows you to have truly self-contained aspect components. Those are easier to maintain, refactor and reuse as well as build libraries upon. The drawback is that it requires an additional post-compilation step (until java 1.5) to annotate them with the metadata.