JDK 5.0 has introduced a new concept called annotations. Annotations can be used as an alternative to XML for configuring classes for AOP. For backward compatibility with JDK 1.4.2 JBoss AOP uses an annotation compiler allowing you to create the same annotations in javadoc style comments.
The JDK 1.5 form has been used for the declarations of each annotation type shown below. For clarity both types of annotations are shown in the usage examples contained in this chapter. A point worth mentioning is that in JDK 1.5 annotations are part of language and can thus be imported, so that just the classname can be used. In JDK 1.4.2 the annotations are not part of "Java" so fully qualified classnames are needed. To keep things short and sweet the listings only import classes that are new for each listing.
To mark a class as an aspect you annotate it with the @Aspect annotation. Remember that a class to be used as an aspect does not need to inherit or implement anything special, but it must have an empty constuctor and contain one or more methods (advices) of the format:
public Object <any-method-name>(org.jboss.aop.joinpoint.Invocation)
The declaration of org.jboss.aop.Aspect is:
package org.jboss.aop; import org.jboss.aop.advice.Scope; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Aspect { Scope scope() default Scope.PER_VM; }
and Scope is:
package org.jboss.aop.advice; public enum Scope { PER_VM, PER_CLASS, PER_INSTANCE, PER_JOINPOINT }
See the "XML Bindings" chapter for a description of the various scopes.
In JDK 1.5 we use the @Aspect annotation as follows:
package com.mypackage; import org.jboss.aop.Aspect; import org.jboss.aop.advice.Scope; import org.jboss.aop.joinpoint.Invocation; @Aspect (scope = Scope.PER_VM) public class MyAspect { public Object myAdvice(Invocation invocation) }
And in JDK 1.4.2:
package com.mypackage; /** * @@Aspect (scope = Scope.PER_VM) */ public class MyAspect { public Object myAdvice(Invocation invocation) { return invocation.invokeNext(); } }
The name of the class (in this case com.mypackage.MyAspect) gets used as the internal name of the aspect. The equivalent using XML configuration would be:
<aop> <aspect class="com.mypackage.MyAspect" scope="PER_VM"/> </aop>
To mark a class as an interceptor or an aspect factory you annotate it with the @InterceptorDef annotation. The class must either implement the org.jboss.aop.advice.Interceptor interface or the org.jboss.aop.advice.AspectFactory interface.
The declaration of org.jboss.aop.InterceptorDef is:
package org.jboss.aop; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Aspect { Scope scope() default Scope.PER_VM; }
The same Scope enum is used as for Aspect. The following examples use the @Bind annotation, which will be described in more detail below.
In JDK 1.5 we use the @InterceptorDef annotation to mark an Interceptor as follows:
package com.mypackage; import org.jboss.aop.Bind; import org.jboss.aop.InterceptorDef; import org.jboss.aop.advice.Interceptor; @InterceptorDef (scope = Scope.PER_VM) @Bind (pointcut="execution("* com.blah.Test->test(..)") public class MyInterceptor implements Interceptor { public Object invoke(Invocation invocation)throws Throwable { return invocation.invokeNext(); } }
And in JDK 1.4.2:
package com.mypackage; /** * @@org.jboss.aop.InterceptorDef (scope = org.jboss.aop.advice.Scope.PER_VM) * @@org.jboss.aop.Bind (pointcut="execution("* com.blah.Test->test(..)") */ public class MyInterceptor implements Interceptor { public Object invoke(Invocation invocation)throws Throwable { return invocation.invokeNext(); } }
The name of the class (in this case com.mypackage.MyInterceptor) gets used as the class name of the interceptor. The equivalent using XML configuration would be:
<aop> <interceptor class="com.mypackage.MyInterceptor" scope="PER_VM"/> </aop>
In JDK 1.5 the @IntroductionDef annotation is used to mark an AspectFactory as follows:
package com.mypackage; import org.jboss.aop.advice.AspectFactory; @InterceptorDef (scope=org.jboss.aop.advice.Scope.PER_VM) @Bind (pointcut="execution("* com.blah.Test->test2(..)") public class MyInterceptorFactory implements AspectFactory { //Implemented methods left out for brevity }
And in JDK 1.4.2:
package com.mypackage; /** * @@org.jboss.aop.InterceptorDef (scope=org.jboss.aop.advice.Scope.PER_VM) * @@org.jboss.aop.Bind (pointcut="execution("* com.blah.Test->test2(..)") */ public class MyInterceptorFactory implements AspectFactory { //Implemented methods left out for brevity }
The name of the class (in this case com.mypackage.MyInterceptorFactory) gets used as the factory name of the aspect factory. The equivalent using XML configuration would be:
<aop> <interceptor factory="com.mypackage.MyInterceptorFactory" scope="PER_VM"/> </aop>
To define a named pointcut you annotate a field within an @Aspect or @InterceptorDef annotated class with @PointcutDef. @PointcutDef only applies to fields and is not recognised outside @Aspect or @InterceptorDef annotated classes.
The declaration of org.jboss.aop.PointcutDef is:
package org.jboss.aop; @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface PointcutDef { String value(); }
@PointcutDef takes only one value, a valid pointcut expression. The name of the pointcut used internally and when yo want to reference it is:
<name of @Aspect/@InterceptorDef annotated class>.<name of @PointcutDef annotated field>
An example of an aspect class containing a named pointcut which it references from a bindng's pointcut expression in JDK 1.5:
package com.mypackage; import org.jboss.aop.PointcutDef; import org.jboss.aop.pointcut.Pointcut; @Aspect (scope = Scope.PER_VM) public class MyAspect { @PointcutDef ("(execution("* org.blah.Foo->someMethod()) OR \ execution("* org.blah.Foo->otherMethod()))") public static Pointcut fooMethods; public Object myAdvice(Invocation invocation) { return invocation.invokeNext(); } }
It is worth noting that named pointcuts can be referenced in pointcut expressions outside the class they are declared in (if the annotated fields are declared public of course!).
The same example in JDK 1.4.2:
package com.mypackage; import org.jboss.aop.pointcut.Pointcut; /** * @@org.jboss.aop.Aspect (scope = Scope.PER_VM) */ public class MyAspect { /** * @@org.jboss.aop.PointcutDef ("(execution("* org.blah.Foo->someMethod()) \ OR execution("* org.blah.Foo->otherMethod()))") */ public static Pointcut fooMethods; public Object myAdvice(Invocation invocation) { return invocation.invokeNext(); } }
Using XML configuration this would be:
<aop> <aspect class="com.mypackage.MyAspect" scope="PER_VM"/> <pointcut name="com.mypackage.MyAspect.fooMethods" expr="(execution("* org.blah.Foo->someMethod()) OR \ execution("* org.blah.Foo->otherMethod()))" /> </aop>
To create a binding to an advice method from an aspect class, you annotate the advice method with @Bind. To create a binding to an Interceptor or AspectFactory, you annotate the class itself with @Bind since Interceptors only contain one advice (the invoke() method). The @Bind annotation will only be recognised in the situations just mentioned.
The declaration of org.jboss.aop.Bind is:
package org.jboss.aop; @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Bind { String pointcut(); String cflow() default ""; }
The @Bind annotation takes two parameters:
In the case of a binding to an advice in an aspect class, the internal name of the binding becomes:
<name of the aspect class>.<the name of the advice method>
In the case of a binding to an Interceptor or AspectFactory implementation, the internal name of the binding becomes:
<name of the Interceptor/AspectFactory implementation class>
An example of a binding using an advice method in an aspect class in JDK 1.5:
package com.mypackage; import org.jboss.aop.Bind; @Aspect (scope = Scope.PER_VM) public class MyAspect { @PointcutDef ("(execution("* org.blah.Foo->someMethod()) \ OR execution("* org.blah.Foo->otherMethod()))") public static Pointcut fooMethods; @Bind (pointcut="com.mypackage.MyAspect.fooMethods") public Object myAdvice(Invocation invocation) { return invocation.invokeNext(); } @Bind (pointcut="execution("* org.blah.Bar->someMethod())") public Object myAdvice(Invocation invocation) { return invocation.invokeNext(); } }
And in JDK 1.4.2:
package com.mypackage; /** * @@org.jboss.aop.Aspect (scope = Scope.PER_VM) */ public class MyAspect { /** * @@org.jboss.aop.PointcutDef ("(execution("* org.blah.Foo->someMethod()) \ OR execution("* org.blah.Foo->otherMethod()))") */ public static Pointcut fooMethods; /** * @@org.jboss.aop.Bind (pointcut="com.mypackage.MyAspect.fooMethods") */ public Object myAdvice(Invocation invocation) { return invocation.invokeNext(); } /** * @@org.jboss.aop.Bind (pointcut="execution("* org.blah.Bar->someMethod())") */ public Object otherAdvice(Invocation invocation) { return invocation.invokeNext(); } }
The equivalent using XML configuration would be:
<aop> <aspect class="com.mypackage.MyAspect" scope="PER_VM"/> <pointcut name="com.mypackage.MyAspect.fooMethods" expr="(execution("* org.blah.Foo->someMethod()) OR \ execution("* org.blah.Foo->otherMethod()))" /> <bind pointcut="com.mypackage.MyAspect.fooMethods"> <advice name="myAdvice" aspect="com.mypackage.MyAspect"> </bind> <bind pointcut="execution("* org.blah.Bar->someMethod())"> <advice name="otherAdvice" aspect="com.mypackage.MyAspect"> </bind> </aop>
Revisiting the examples above in the @InterceptorDef section, now that we know what @Bind means, the equivalent using XML configuration would be:
<aop> <interceptor class="com.mypackage.MyInterceptor" scope="PER_VM"/> <interceptor factory="com.mypackage.MyInterceptorFactory" scope="PER_VM"/> <bind pointcut="execution("* com.blah.Test->test2(..)"> <interceptor-ref name="com.mypackage.MyInterceptor"/> </bind> <bind pointcut="execution("* com.blah.Test->test2(..)"> <interceptor-ref name="com.mypackage.MyInterceptorFactory"/> </bind> </aop>
Interface introductions can be done using the @Introduction annotation. Only fields within a class annotated with @Aspect or @InterceptorDef can be annotated with @Introduction.
The declaration of org.jboss.aop.Introduction:
package org.jboss.aop; @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Introduction { Class target() default java.lang.Class.class; String typeExpression() default ""; Class[] interfaces(); }
The parameters of @Introduction are:
target or typeExpression has to be specified, but not both.
This is how to use @Introduction in JDK 1.5:
package com.mypackage; import org.jboss.aop.Introduction; @Aspect (scope = Scope.PER_VM) public class IntroAspect { @Introduction (target=com.blah.SomeClass.class, \ interfaces={java.io.Serializable.class}) public static Object pojoNoInterfacesIntro; }
And in JDK 1.4.2:
package com.mypackage; /* * @@org.jboss.aop.Aspect (scope = Scope.PER_VM) */ public class IntroAspect { /* * @org.jboss.aop.Introduction (target=com.blah.SomeClass, \ interfaces={java.io.Serializable}) */ public static Object pojoNoInterfacesIntro; }
Notice the slight difference in the JDK 1.4.2 annotation, the class values don't have the ".class" suffix.
This means make com.blah.SomeClass.class implement the java.io.Serializable interface. The equivalent configured via XML would be:
<introduction class="com.blah.SomeClass.class"> <interfaces> java.io.Serializable </interfaces> </introduction>
Sometimes when we want to introduce/force a new class to implement an interface, that interface introduces new methods to a class. The class needs to implement these methods to be valid. In these cases a mixin class is used. The mixin class must implement the methods specified by the interface(s) and the main class can then implement these methods and delegate to the mixin class.
Mixins are created using the @Mixin annotation. Only methods within a class annotated with @Aspect or @InterceptorDef can be annotated with @Mixin. The annotated method has
The declaration of org.jboss.aop.Mixin:
package org.jboss.aop; @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Mixin { Class target() default java.lang.Class.class; String typeExpression() default ""; Class[] interfaces(); boolean isTransient() default true; }
The parameters of @Mixin are:
target or typeExpression has to be specified, but not both.
An example aspect using @Mixin in JDK 1.5:
package com.mypackage; import org.jboss.aop.Mixin; import com.mypackage.POJO; @Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) public class IntroductionAspect { @Mixin (target=com.mypackage.POJO.class, interfaces={java.io.Externalizable.class}) public static ExternalizableMixin createExternalizableMixin(POJO pojo) { return new ExternalizableMixin(pojo); } }
Here's the JDK 1.4.2 version:
package com.mypackage; import org.jboss.aop.Mixin; import com.mypackage.POJO; /** * @@org.jboss.aop.Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) */ public class IntroductionAspect { /** * @org.jboss.aop.Mixin (target=com.mypackage.POJO.class, \ interfaces={java.io.Externalizable.class}) */ public static ExternalizableMixin createExternalizableMixin(POJO pojo) { return new ExternalizableMixin(pojo); } }
Since this is slightly more complex than the previous examples we have seen, the POJO and ExternalizableMixin classes are included here.
package com.mypackage; public class POJO { String stuff; }
package com.mypackage; import java.io.Externalizable; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectOutput; public class ExternalizableMixin implements Externalizable { POJO pojo; public ExternalizableMixin(POJO pojo) { this.pojo = pojo; } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { pojo.stuff = in.readUTF(); } public void writeExternal(ObjectOutput out) throws IOException { out.writeUTF(pojo.stuff); } }
This has the same effect as the following XML configuration:
<introduction classs="com.mypackage.POJO"> <mixin transient="true"> <interfaces> java.io.Externalizable </interfaces> <class>com.mypackage.ExternalizableMixin</class> <construction>IntroductionAspect.createExternalizableMixin(this)</construction> </mixin> </introduction>
To prepare a joinpoint or a set of joinpoints for DynamicAOP annotate a field with @Prepare in a class anotated with @Aspect or @InterceptorDef.
The declaration of org.jboss.aop.Prepare is:
package org.jboss.aop; @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface Prepare { String value() default ""; }
The single field value contains a pointcut expression matching one or more joinpoints.
To use @Prepare in JDK 1.5:
package com.mypackage; import org.jboss.aop.Prepare; @InterceptorDef (scope = Scope.PER_VM) @Bind (pointcut="execution("* com.blah.Test->test(..)") public class MyInterceptor2 implements Interceptor { @Prepare ("all(com.blah.DynamicPOJO)") public static Pointcut dynamicPOJO; public Object invoke(Invocation invocation)throws Throwable { return invocation.invokeNext(); } }
And in JDK 1.4.2:
package com.mypackage; /** * @@org.jboss.aop.InterceptorDef (scope = org.jboss.aop.advice.Scope.PER_VM) * @@org.jboss.aop.Bind (pointcut="execution("* com.blah.Test->test(..)") */ public class MyInterceptor2 implements Interceptor { /** * @Prepare ("all(com.blah.DynamicPOJO)") */ public static Pointcut dynamicPOJO; public Object invoke(Invocation invocation)throws Throwable { return invocation.invokeNext(); } }
Using XML configuration instead we would write:
<prepare expr="all(com.blah.DynamicPOJO)"/>
This simple example used an @InterceptorDef class for a bit of variety in the examples, and to reiterate that @Pointcut, @Introduction, @Mixin, @Prepare, @Typedef, @CFlow, @DynamicCFlow and @AnnotationIntroductionDef can all be used both in @InterceptorDef annotated classes AND @Aspect annotated classes. Same for @Bind, but that is a special case as mentioned above.
To use a typedef, you annotate a field with @TypeDef in a class anotated with @Aspect or @InterceptorDef.
The declaration of org.jboss.aop.TypeDef:
package org.jboss.aop; @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface TypeDef { String value(); }
The single value field takes a type expression that resolves to one or more classes. The name of the typedef used for reference and internally is:
<name of @Aspect/@InterceptorDef annotated class>.<name of @TypeDef annotated field>
Here's how to use it with JDK 1.5:
package com.mypackage; import org.jboss.aop.TypeDef; import org.jboss.aop.pointcut.Typedef; @Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) public class TypedefAspect { @TypeDef ("class(com.blah.POJO)") public static Typedef myTypedef; @Bind (pointcut="execution(* \ $typedef{com.mypackage.TypedefAspect.myTypedef}->methodWithTypedef())") public Object typedefAdvice(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
And with JDK 1.4.2:
package com.mypackage; import org.jboss.aop.TypeDef; import org.jboss.aop.pointcut.Typedef; /** * @@org.jboss.aop.Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) */ public class TypedefAspect { /** * @@org.jboss.aop.TypeDef ("class(com.blah.POJO)") */ public static Typedef myTypedef; /** * @@org.jboss.aop.Bind (pointcut="execution(* \ $typedef{com.mypackage.TypedefAspect.myTypedef}->methodWithTypedef())") */ public Object typedefAdvice(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
The equivalent using XML configuration would be:
<aop> <aspect class="com.mypackage.TypedefAspect" scope="PER>VM"/> <typedef name="com.mypackage.TypedefAspect.myTypedef" expr="class(com.blah.POJO)"/> <bind pointcut="execution(* \ $typedef{com.mypackage.TypedefAspect.myTypedef}->methodWithTypedef())" > <advice name="typedefAdvice" aspect="com.mypackage.TypedefAspect"/> </bind> </aop>
To create a CFlow stack, you annotate a field with @CFlowDef in a class anotated with @Aspect or @InterceptorDef. The declaration of org.jboss.aop.CFlowStackDef is:
package org.jboss.aop; @Target({ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface CFlowStackDef { CFlowDef[] cflows(); }
In turn the declaration of org.jboss.aop.CFlowDef is:
package org.jboss.aop; public @interface CFlowDef { boolean called(); String expr(); }
The parameters of @CFlowDef are:
The name of the CFlowStackDef used for reference and internally is:
<name of @Aspect/@InterceptorDef annotated class>.<name of @CFlowStackDef annotated field>
CFlowStackDef is used like this in JDK 1.5:
package com.mypackage; import org.jboss.aop.CFlowStackDef; import org.jboss.aop.pointcut.CFlowStack; @Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) public class CFlowAspect { @CFlowStackDef (cflows={@CFlowDef(expr= "void com.blah.POJO->cflowMethod1()", \ called=false), @CFlowDef(expr = "void com.blah.POJO->cflowMethod2()", \ called=true)}) public static CFlowStack cfNot1And2Stack; @Bind (pointcut="execution(void com.blah.POJO*->privMethod())", \ cflow="com.mypackage.CFlowAspect.cfNot1And2Stack") public Object cflowAdvice(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
And in 1.4.2:
package com.mypackage; import org.jboss.aop.pointcut.CFlowStack; /** * @@org.jboss.aop.Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) */ public class CFlowAspect { /** * @@org.jboss.aop.CFlowStackDef (cflows={@org.jboss.aop.CFlowDef \ (expr= "void com.blah.POJO->cflowMethod1()", called=false), \ @org.jboss.aop.CFlowDef (expr = "void com.blah.POJO->cflowMethod2()", \ called=true)}) */ public static CFlowStack cfNot1And2Stack; /** * @@org.jboss.aop.Bind (pointcut="execution(void com.blah.POJO*->privMethod())", \ cflow="com.mypackage.CFlowAspect.cfNot1And2Stack") */ public Object cflowAdvice(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
The above means the same as this XML:
<aop> <cflow-stack name="com.mypackage.CFlowAspect.cfNot1And2Stack"> <called expr="void com.blah.POJO->cflowMethod1()"/> <not-called expr="void com.blah.POJO->cflowMethod2()"/> </cflow-stack> </aop>
To create a dynamic CFlow you annotate a class implementing org.jboss.aop.pointcut.DynamicCFlow with @DynamicCFlowDef. The declaration of @org.jboss.aop.DynamicCFlowDef is:
package org.jboss.aop; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DynamicCFlowDef { }
Here is a @DynamicCFlow annotated class in JDK 1.5:
package com.mypackage; import org.jboss.aop.DynamicCFlowDef; import org.jboss.aop.pointcut.DynamicCFlow; @DynamicCFlowDef public class MyDynamicCFlow implements DynamicCFlow { public static boolean execute = false; public boolean shouldExecute(Invocation invocation) { return execute; } }
And the same in JDK 1.4.2:
package com.mypackage; import org.jboss.aop.pointcut.DynamicCFlow; /** * @org.jboss.aop.DynamicCFlowDef */ public class MyDynamicCFlow implements DynamicCFlow { public static boolean execute = false; public boolean shouldExecute(Invocation invocation) { return execute; } }
The name of the @DynamicCFlowDef annotated class gets used as the name of the cflow for references.
To use the dynamic cflow we just defined in JDK 1.5:
package com.mypackage; @Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) public class CFlowAspect { @Bind (pointcut="execution(void com.blah.POJO->someMethod())", \ cflow="com.mypackage.MyDynamicCFlow") public Object cflowAdvice(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
To use the dynamic cflow we just defined in JDK 1.5:
package com.mypackage; /** * @@org.jboss.aop.Aspect (scope=org.jboss.aop.advice.Scope.PER_VM) */ public class CFlowAspect { /** * @@org.jboss.aop.Bind (pointcut="execution(void com.blah.POJO->someMethod())", \ cflow="com.mypackage.MyDynamicCFlow") */ public Object cflowAdvice(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
You can introduce annotations by annotating a field with the @AnnotationIntroductionDef in a class anotated with @Aspect or @InterceptorDef. The declaration of org.jboss.aop.AnnotationIntroductionDef is:
package org.jboss.aop; @Target (ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationIntroductionDef { String expr(); boolean invisible(); String annotation(); }
The parameters of @AnnotationIntroductionDef are:
The listings below make use of an annotation called @com.mypackage.MyAnnotation:
package com.mypackage; public interface MyAnnotation { String string(); int integer(); boolean bool(); }
What its parameters mean is not very important for our purpose.
The use of @AnnotationIntroductionDef in JDK 1.5:
package com.mypackage; import org.jboss.aop.AnnotationIntroductionDef: import org.jboss.aop.introduction.AnnotationIntroduction; @.InterceptorDef (scope=org.jboss.aop.advice.Scope.PER_VM) @org.jboss.aop.Bind (pointcut="all(com.blah.SomePOJO)") public class IntroducedAnnotationInterceptor implements Interceptor { @org.jboss.aop.AnnotationIntroductionDef \ (expr="method(* com.blah.SomePOJO->annotationIntroductionMethod())", \ invisible=false, \ annotation="@com.mypackage.MyAnnotation \ (string='hello', integer=5, bool=true)") public static AnnotationIntroduction annotationIntroduction; public String getName() { return "IntroducedAnnotationInterceptor"; } public Object invoke(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
Note that the reference to @com.mypackage.MyAnnotation must use the fully qualified class name, and that the value for its string parameter uses single quotes.
The use of @AnnotationIntroductionDef in JDK 1.4.2:
package com.mypackage; import org.jboss.aop.introduction.AnnotationIntroduction; /** * @@org.jboss.aop.InterceptorDef (scope=org.jboss.aop.advice.Scope.PER_VM) * @@org.jboss.aop.Bind (pointcut="all(com.blah.SomePOJO)") */ public class IntroducedAnnotationInterceptor implements Interceptor { /** * @@org.jboss.aop.AnnotationIntroductionDef \ (expr="method(* com.blah.SomePOJO->annotationIntroductionMethod())", \ invisible=false, \ annotation="@com.mypackage.MyAnnotation \ (string='hello', integer=5, bool=true)") */ public static AnnotationIntroduction annotationIntroduction; public String getName() { return "IntroducedAnnotationInterceptor"; } public Object invoke(Invocation invocation) throws Throwable { return invocation.invokeNext(); } }
Note that the reference to only uses one '@', and that the value for its string parameter uses single quotes.
The previous listings are the same as this XML configuration:
<annotation-introduction expr="method(* com.blah.SomePOJO->annotationIntroductionMethod()) invisible="false" > @com.mypackage.MyAnnotation (string="hello", integer=5, bool=true) </annotation-introduction>