metadata-aop.xml
. This is the source file for where our annotations will be declared.
This file is composed of a list of metadata
tags. Each such tag must have two attributes:
tag
and class
. The tag
attribute is the name of the metadata, equivalent to the name of an annotation. The
class
attribute must contain a class expression. Every class matching that expression will be bound to the metadata.
Take a look at the two first tags of metadata-aop.xml
:
<metadata tag="Trace" class="POJO"> <constructor expr="POJO()"/> </metadata> <metadata tag="Billable" class="POJO"> <constructor expr="POJO()"> <amount>0.01</amount> </constructor> </metadata>
The first one represents a metadata @Trace
and the second
one represents the metadata @Billable
. Both metadata will be applied to class POJO
,
as specified in the class
attribute.
The contents of a metadata
tag indicate to which elements of
POJO
class this metadata should be applied. In the example, the metadata @Trace
will be applied to the
default constructor of POJO(). The metada @Billable
will be also applied to the same constructor, and has an attribute,
amount
, whose value is 0.01
. Following this same format you can define as many attributes and values you
need.
In similar ways, a metadata can be applied to the fields, methods and to the class itself, just like Java annotations. The next
metadata
tags apply metadata to constructors, methods and fields:
<metadata tag="Trace" class="POJO"> <field name="field"/> <constructor expr="POJO(int)"/> <method expr="void someMethod()"/> </metadata> <metadata tag="Billable" class="POJO"> <constructor expr="POJO(int)"> <amount>0.01</amount> </constructor> <method expr="void someMethod()"> <amount>0.05</amountgt; </method> </metadata>If we wanted to apply
@Trace
to POJO
class, we could have added an empty class
XML tag to a metadata
element:
<metadata tag="Trace" class="POJO"> <class/> </metadata>The example bellow states that every constructor, field, and method of
POJO
class will be bound to the
@Trace
metadata:
<metadata tag="Trace" class="POJO"> <default/> </metadata>
<bind pointcut="execution(POJO->@Billable(..))"> <interceptor class="BillingInterceptor"/> </bind> <bind pointcut="execution(* POJO->@Billable(..))"> <interceptor class="BillingInterceptor"/> </bind>
The first binding above says that for every constructor tagged as @Billable
apply the BillingInterceptor
. The second binding states that for any method tagged as @Billable
apply the BillingInterceptor
. Let's now take a look at applying the tracing advice.
<bind pointcut="all(@Trace)"> <interceptor class="TraceInterceptor"/> </bind>
The above states that for any field, constructor, or method tagged as @Trace
, apply the TraceInterceptor
.
_getAdvisor()
or _getInstanceAdvisor()
methods, or you can use the indirection that the Invocation
object provides you. You can use the Invocation
object to resolve metadata based on the context of the execution. BillingInterceptor.java gives an example of this. This interceptor intercepts different kinds of things (methods and constructors), but it doesn't care about the thing it is intercepting, only the metadata.
public Object invoke(Invocation invocation) throws Throwable { System.out.println("billing amount: $" + invocation.getMetaData("Billable", "amount")); }
To compile and run (for further detail, refer to our Compiling and Running Examples Guide):
$ ant run.aopcIt will run the annotationc compiler on the source files to generate metadata in metadata-aop.xml, then javac the files and then run the AOPC precompiler to manipulate the bytecode, then finally run the example. Note that there are two XML aop deployment descriptors: metadata-aop.xml and jboss-aop.xml. The System Property jboss.aop.path can accept a list of files delimited by the platform classpath separator. ';' on windows ':' on unix. Running the example should produce:
run.aopc: [java] --- new POJO(); --- [java] billing amount: $0.01 [java] <<< Trace : executing constructor public POJO() [java] empty constructor [java] >>> Leaving Trace [java] --- new POJO(int); --- [java] billing amount: $0.01 [java] <<< Trace : executing constructor public POJO(int) [java] int constructor [java] >>> Leaving Trace [java] --- pojo.someMethod(); --- [java] billing amount: $0.05 [java] <<< Trace : executing method public void POJO.someMethod() [java] someMethod [java] >>> Leaving Trace [java] --- pojo.field = 55; --- [java] <<< Trace : write field name: public int POJO.field [java] >>> Leaving Trace