aboutsummaryrefslogtreecommitdiffstats
path: root/docs/adk15notebook/ataspectj.xml
diff options
context:
space:
mode:
Diffstat (limited to 'docs/adk15notebook/ataspectj.xml')
-rw-r--r--docs/adk15notebook/ataspectj.xml1144
1 files changed, 1144 insertions, 0 deletions
diff --git a/docs/adk15notebook/ataspectj.xml b/docs/adk15notebook/ataspectj.xml
new file mode 100644
index 000000000..7f8152d9c
--- /dev/null
+++ b/docs/adk15notebook/ataspectj.xml
@@ -0,0 +1,1144 @@
+<chapter id="ataspectj" xreflabel="AtAspectJ">
+
+ <title>An Annotation Based Development Style</title>
+
+ <sect1 id="ataspectj-intro">
+ <title>Introduction</title>
+
+ <para>In addition to the familiar AspectJ code-based style of aspect
+ declaration, AspectJ 5 also supports an annotation-based style of
+ aspect declaration. We informally call the set of annotations that
+ support this development style the "@AspectJ" annotations.</para>
+
+ <para>
+ AspectJ 5 allows aspects and their members to be specified using
+ either the code style or the annotation style. Whichever style you
+ use, the AspectJ weaver ensures that your program has exactly the
+ same semantics. It is, to quote a famous advertising campaign,
+ "a choice, not a compromise". The two styles can be mixed within
+ a single application, and even within a single source file, though
+ we doubt this latter mix will be recommended in practice.
+ </para>
+
+ <para>
+ The use of the @AspectJ annotations means that there are large
+ classes of AspectJ applications that can be compiled by a regular
+ Java 5 compiler, and subsequently woven by the AspectJ weaver (for
+ example, as an additional build stage, or as late as class load-time).
+ In this chapter we introduce the @AspectJ annotations and show how
+ they can be used to declare aspects and aspect members.
+ </para>
+
+ </sect1>
+
+ <sect1 id="ataspectj-aspects">
+ <title>Aspect Declarations</title>
+
+ <para>
+ Aspect declarations are supported by the
+ <literal>org.aspectj.lang.annotation.Aspect</literal>
+ annotation.
+ The declaration:
+ </para>
+
+ <programlisting><![CDATA[
+@Aspect
+public class Foo {}
+]]></programlisting>
+
+ <para>Is equivalent to:</para>
+
+ <programlisting><![CDATA[
+public aspect Foo {}
+]]></programlisting>
+
+ <para>To specify an aspect an aspect instantiation model (the default is
+ singleton), provide the perclause as the
+ <literal>@Aspect</literal>
+ value.
+ For example:
+ </para>
+
+ <programlisting><![CDATA[
+@Aspect("perthis(execution(* abc..*(..)))")
+public class Foo {}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+public aspect Foo perthis(execution(* abc..*(..))) {}
+]]></programlisting>
+
+ <sect2 id="limitations" xreflabel="limitations">
+ <title>Limitations</title>
+
+ <para>Privileged aspects are not supported by the annotation style.</para>
+ <!--
+ <programlisting><![CDATA[
+@Aspect(isPrivileged=true)
+public class Foo {}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+public privileged aspect Foo {}
+]]></programlisting>
+ -->
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="ataspectj-pcadvice">
+ <title>Pointcuts and Advice</title>
+
+ <para>
+ Pointcut and advice declarations can be made using the
+ <literal>Pointcut, Before, After, AfterReturning, AfterThrowing,</literal>
+ and
+ <literal>Around</literal>
+ annotations.
+ </para>
+
+ <sect2 id="pointcuts" xreflabel="pointcuts">
+ <title>Pointcuts</title>
+
+ <para>
+ Pointcuts are specified using the
+ <literal>org.aspectj.lang.annotation.Pointcut</literal>
+ annotation
+ on a method declaration. The method should have a
+ <literal>void</literal>
+ return type. The parameters of the method correspond to the parameters
+ of the pointcut. The modifiers of the method correspond to the modifiers
+ of the pointcut.
+ </para>
+
+ <para>
+ As a general rule, the
+ <literal>@Pointcut</literal>
+ annotated method must have an empty method body
+ and must not have any
+ <literal>throws</literal>
+ clause. If formal are bound (using
+ <literal>args(), target(), this(), @args(), @target(), @this(), @annotation())</literal>
+ in the
+ pointcut, then they must appear in the method signature.
+ </para>
+
+ <para>
+ The
+ <literal>if()</literal>
+ pointcut is treated specially and is discussed in a later section.
+ </para>
+
+ <para>Here is a simple example of a pointcut declaration in both code and @AspectJ styles:</para>
+
+ <programlisting><![CDATA[
+@Pointcut("call(* *.*(..))")
+void anyCall() {}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+pointcut anyCall() : call(* *.*(..));
+]]></programlisting>
+
+
+ <para>When binding arguments, simply declare the arguments as normal in the annotated method:</para>
+
+ <programlisting><![CDATA[
+@Pointcut("call(* *.*(int)) && args(i) && target(callee)")
+void anyCall(int i, Foo callee) {}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+pointcut anyCall(int i, Foo callee) : call(* *.*(int)) && args(i) && target(callee);
+]]></programlisting>
+
+ <para>An example with modifiers (Remember that Java 5 annotations are not
+ inherited, so the <literal>@Pointcut</literal> annotation must be
+ present on the extending aspect's pointcut declaration too):</para>
+
+ <programlisting><![CDATA[
+@Pointcut("")
+protected abstract void anyCall();
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+protected abstract pointcut anyCall();
+]]></programlisting>
+
+ <sect3>
+ <title>Type references inside @AspectJ annotations</title>
+
+ <para>
+ Using the code style, types referenced in pointcut expressions are
+ resolved with respect to the imported types in the compilation unit.
+ When using the annotation style, types referenced in pointcut
+ expressions are resolved in the absence of any imports and so have
+ to be fully qualified if they are not by default visible to the
+ declaring type (outside of the declaring package and
+ <literal>java.lang</literal>
+ ). This
+ does not apply to type patterns with wildcards, which are always resolved
+ in a global scope.
+ </para>
+
+ <para>
+ Consider the following compilation unit:
+ </para>
+
+ <programlisting><![CDATA[
+package org.aspectprogrammer.examples;
+
+import java.util.List;
+
+public aspect Foo {
+ pointcut listOperation() : call(* List.*(..));
+ pointcut anyUtilityCall() : call(* java.util..*(..));
+}
+]]></programlisting>
+
+ <para>
+ Using the annotation style this would be written as:
+ </para>
+
+ <programlisting><![CDATA[
+package org.aspectprogrammer.examples;
+
+import java.util.List; // redundant but harmless
+
+@Aspect
+public class Foo {
+ @Pointcut("call(* java.util.List.*(..))") // must qualify
+ void listOperation() {}
+
+ @Pointcut("call(* java.util..*(..))")
+ void anyUtilityCall() {}
+}
+]]></programlisting>
+
+ </sect3>
+
+ <sect3>
+ <title>if() pointcut expressions</title>
+
+ <para>In code style, it is possible to use the
+ <literal>if(...)</literal>
+ poincut to define
+ a conditional pointcut expression which will be evaluated at runtime for each candidate join point.
+ The
+ <literal>if(...)</literal>
+ body can be any valid Java boolean expression, and can use any exposed formal, as well as the join
+ point forms
+ <literal>thisJoinPoint, thisJoinPointStaticPart and thisJoinPointEnclosingStaticPart</literal>
+ .
+ </para>
+
+ <para>
+ When using the annotation style, it is not possible to write a full Java expression
+ within
+ the annotation value so the syntax differs slightly, whilst providing the very same
+ semantics and runtime behaviour. An
+ <literal>if()</literal>
+ pointcut expression can be
+ declared in an
+ <literal>@Pointcut</literal>
+ , but must have either an empty body (<literal>if()</literal>, or be one
+ of the expression forms
+ <literal>if(true)</literal>
+ or
+ <literal>if(false)</literal>
+ . The annotated
+ method must be public, static, and return a boolean. The body of the method contains the
+ condition to be evaluated. For example:
+ </para>
+
+ <programlisting><![CDATA[
+@Pointcut("call(* *.*(int)) && args(i) && if()")
+public static boolean someCallWithIfTest(int i) {
+ return i > 0;
+}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+pointcut someCallWithIfTest(int i) : call(* *.*(int)) && args(i) && if(i > 0);
+]]></programlisting>
+
+ <para>and the following is also a valid form:</para>
+
+ <programlisting><![CDATA[
+static int COUNT = 0;
+
+@Pointcut("call(* *.*(int)) && args(i) && if()")
+public static boolean someCallWithIfTest(int i, JoinPoint jp, JoinPoint.EnclosingStaticPart esjp) {
+ // any legal Java expression...
+ return i > 0
+ && jp.getSignature().getName.startsWith("doo")
+ && esjp.getSignature().getName().startsWith("test")
+ && COUNT++ < 10;
+}
+
+@Before("someCallWithIfTest(anInt, jp, enc)")
+public void beforeAdviceWithRuntimeTest(int anInt, JoinPoint jp, JoinPoint.EnclosingStaticPart enc) {
+ //...
+}
+
+// Note that the following is NOT valid
+/*
+@Before("call(* *.*(int)) && args(i) && if()")
+public void advice(int i) {
+ // so you were writing an advice or an if body ?
+}
+*/
+]]></programlisting>
+
+ <para>
+ It is thus possible with the annotation style to use the
+ <literal>if()</literal>
+ pointcut
+ only within an
+ <literal>@Pointcut</literal>
+ expression. The
+ <literal>if()</literal>
+ must not contain any
+ body. The annotated
+ <literal>@Pointcut</literal>
+ method must then be of the form
+ <literal>public static boolean</literal>
+ and can use formal bindings as usual.
+ Extra
+ <emphasis>implicit</emphasis>
+ arguments of type JoinPoint, JoinPoint.StaticPart and JoinPoint.EnclosingStaticPart can also be used
+ (this is not permitted for regular annotated pointcuts not using the
+ <literal>if()</literal>
+ form).
+ </para>
+
+ <para>
+ The special forms
+ <literal>if(true)</literal>
+ and
+ <literal>if(false)</literal>
+ can be used in a more
+ general way and don't imply that the pointcut method must have a body.
+ You can thus write
+ <literal>@Before("somePoincut() &amp;&amp; if(false)")</literal>
+ .
+ </para>
+
+ </sect3>
+
+ </sect2>
+
+ <sect2 id="advice" xreflabel="advice">
+ <title>Advice</title>
+
+ <para>In this section we first discuss the use of annotations for
+ simple advice declarations. Then we show how
+ <literal>thisJoinPoint</literal>
+ and its siblings are handled in the body of advice and discuss the
+ treatment of
+ <literal>proceed</literal>
+ in around advice.
+ </para>
+
+ <para>Using the annotation style, an advice declaration is written as
+ a regular Java method with one of the
+ <literal>Before, After, AfterReturning,
+ AfterThrowing,</literal>
+ or
+ <literal>Around</literal>
+ annotations. Except in
+ the case of around advice, the method should return void. The method should
+ be declared public.
+ </para>
+
+ <para>A method that has an advice annotation is treated exactly as an
+ advice declaration by AspectJ's weaver. This includes the join points that
+ arise when the advice is executed (an adviceexecution join point, not a
+ method execution join point).</para>
+
+ <para>The following example shows a simple before advice declaration in
+ both styles:</para>
+
+ <programlisting><![CDATA[
+@Before("call(* org.aspectprogrammer..*(..)) && this(Foo)")
+public void callFromFoo() {
+ System.out.println("Call from Foo");
+}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+before() : call(* org.aspectprogrammer..*(..)) && this(Foo) {
+ System.out.println("Call from Foo");
+}
+]]></programlisting>
+
+
+ <!--
+ AMC: enhanced adviceexecution pointcuts and @AdviceName will most likely not make AJ5 1.5.0
+
+ <para>Notice one slight difference between the two advice declarations: in
+ the annotation style, the advice has a name, "callFromFoo". Even though
+ advice cannot be invoked explicitly, this name is useful in join point
+ matching when advising advice execution. For this reason, and to preserve
+ exact semantic equivalence between the two styles, we also support the
+ <literal>org.aspectj.lang.annotation.AdviceName</literal> annotation.
+ The exact equivalent declarations are:
+ </para>
+
+ <programlisting><![CDATA[
+@AdviceName("callFromFoo")
+before() : call(* org.aspectprogrammer..*(..)) && this(Foo) {
+ System.out.println("Call from Foo");
+}
+
+is equivalent to...
+
+@Before("call(* org.aspectprogrammer..*(..)) && this(Foo)")
+public void callFromFoo() {
+ System.out.println("Call from Foo");
+}
+]]></programlisting>
+ -->
+
+ <para>If the advice body needs to know which particular
+ <literal>Foo</literal>
+ instance
+ is making the call, just add a parameter to the advice declaration.
+ </para>
+
+ <programlisting><![CDATA[
+before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) {
+ System.out.println("Call from Foo: " + foo);
+}
+]]></programlisting>
+
+ <para>can be written as:</para>
+
+ <programlisting><![CDATA[
+@Before("call(* org.aspectprogrammer..*(..)) && this(foo)")
+public void callFromFoo(Foo foo) {
+ System.out.println("Call from Foo: " + foo);
+}
+]]></programlisting>
+
+ <para>If the advice body needs access to
+ <literal>thisJoinPoint</literal>
+ ,
+ <literal>thisJoinPointStaticPart</literal>
+ ,
+ <literal>thisEnclosingJoinPointStaticPart</literal>
+ then these need to
+ be declared as additional method parameters when using the annotation
+ style.
+ </para>
+
+ <programlisting><![CDATA[
+@Before("call(* org.aspectprogrammer..*(..)) && this(foo)")
+public void callFromFoo(JoinPoint thisJoinPoint, Foo foo) {
+ System.out.println("Call from Foo: " + foo + " at "
+ + thisJoinPoint);
+}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+before(Foo foo) : call(* org.aspectprogrammer..*(..)) && this(foo) {
+ System.out.println("Call from Foo: " + foo + " at "
+ + thisJoinPoint);
+}
+]]></programlisting>
+
+ <para>Advice that needs all three variables would be declared:</para>
+
+ <programlisting><![CDATA[
+@Before("call(* org.aspectprogrammer..*(..)) && this(Foo)")
+public void callFromFoo(JoinPoint thisJoinPoint,
+ JoinPoint.StaticPart thisJoinPointStaticPart,
+ JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart) {
+ // ...
+}
+]]></programlisting>
+
+ <para>
+ <literal>JoinPoint.EnclosingStaticPart</literal>
+ is a new (empty) sub-interface
+ of
+ <literal>JoinPoint.StaticPart</literal>
+ which allows the AspectJ weaver to
+ distinguish based on type which of
+ <literal>thisJoinPointStaticPart</literal>
+ and
+ <literal>thisEnclosingJoinPointStaticPart</literal>
+ should be passed in a given
+ parameter position.
+ </para>
+
+ <para>
+ <literal>After</literal>
+ advice declarations take exactly the same form
+ as
+ <literal>Before</literal>
+ , as do the forms of
+ <literal>AfterReturning</literal>
+ and
+ <literal>AfterThrowing</literal>
+ that do not expose the return type or
+ thrown exception respectively.
+ </para>
+
+ <para>
+ To expose a return value with after returning advice simply declare the returning
+ parameter as a parameter in the method body and bind it with the "returning"
+ attribute:
+ </para>
+
+ <programlisting><![CDATA[
+@AfterReturning("criticalOperation()")
+public void phew() {
+ System.out.println("phew");
+}
+
+@AfterReturning(pointcut="call(Foo+.new(..))",returning="f")
+public void itsAFoo(Foo f) {
+ System.out.println("It's a Foo: " + f);
+}
+]]></programlisting>
+
+ <para>is equivalent to...</para>
+
+ <programlisting><![CDATA[
+after() returning : criticalOperation() {
+ System.out.println("phew");
+}
+
+after() returning(Foo f) : call(Foo+.new(..)) {
+ System.out.println("It's a Foo: " + f);
+}
+]]></programlisting>
+
+ <para>(Note the use of the "pointcut=" prefix in front of the pointcut
+ expression in the returning case).</para>
+
+ <para>After throwing advice works in a similar fashion, using the
+ <literal>throwing</literal>
+ attribute when needing to expose a
+ thrown exception.
+ </para>
+
+ <para>For around advice, we have to tackle the problem of
+ <literal>proceed</literal>
+ .
+ One of the design goals for the annotation style is that a large class of
+ AspectJ applications should be compilable with a standard Java 5 compiler.
+ A straight call to
+ <literal>proceed</literal>
+ inside a method body:
+ </para>
+
+ <programlisting><![CDATA[
+@Around("call(* org.aspectprogrammer..*(..))")
+public Object doNothing() {
+ return proceed(); // CE on this line
+}
+]]></programlisting>
+
+
+ <para>will result in a "No such method" compilation error. For this
+ reason AspectJ 5 defines a new sub-interface of
+ <literal>JoinPoint</literal>
+ ,
+ <literal>ProceedingJoinPoint</literal>
+ .
+ </para>
+
+ <programlisting><![CDATA[
+public interface ProceedingJoinPoint extends JoinPoint {
+ public Object proceed(Object[] args);
+}
+]]></programlisting>
+
+ <para>The around advice given above can now be written as:</para>
+
+ <programlisting><![CDATA[
+@Around("call(* org.aspectprogrammer..*(..))")
+public Object doNothing(ProceedingJoinPoint thisJoinPoint) {
+ return thisJoinPoint.proceed();
+}
+]]></programlisting>
+
+ <para>Here's an example that uses parameters for the proceed call:</para>
+
+ <programlisting><![CDATA[
+@Aspect
+public class ProceedAspect {
+
+ @Pointcut("call(* setAge(..)) && args(i)")
+ void setAge(int i) {}
+
+ @Around("setAge(i)")
+ public Object twiceAsOld(ProceedingJoinPoint thisJoinPoint, int i) {
+ return thisJoinPoint.proceed(new Object[]{i*2}); //using Java 5 autoboxing
+ }
+
+}
+]]></programlisting>
+
+ <para>is equivalent to:</para>
+
+ <programlisting><![CDATA[
+public aspect ProceedAspect {
+ pointcut setAge(int i): call(* setAge(..)) && args(i);
+
+ Object around(int i): setAge(i) {
+ return proceed(i*2);
+ }
+}
+]]></programlisting>
+
+ <para>Note that the ProceedingJoinPoint does not need to be passed to the proceed(..) arguments.
+ </para>
+ <para>In code style, the proceed method has the same signature as the advice, any reordering of
+ actual arguments to the joinpoint that is done in the advice signature must be respected. Annotation
+ style is different. The proceed(..) call takes, in this order:
+ <itemizedlist>
+ <listitem>If 'this()' was used in the pointcut <emphasis>for binding</emphasis>, it must be passed first in proceed(..).
+ </listitem>
+ <listitem>If 'target()' was used in the pointcut <emphasis>for binding</emphasis>, it must be passed next in proceed(..) - it will be the
+ first argument to proceed(..) if this() was not used for binding.
+ </listitem>
+ <listitem>Finally come <emphasis>all</emphasis> the arguments expected at the join point, in the order they
+ are supplied at the join point. Effectively the advice signature is ignored - it doesn't
+ matter if a subset of arguments were bound or the ordering was changed in the advice
+ signature, the proceed(..) calls takes all of them in the right order for the join point.
+ </listitem>
+ </itemizedlist>
+ </para>
+ <para>Since proceed(..) in this case takes an Object array, AspectJ cannot do as much compile time
+ checking as it can for code style. If the rules above aren't obeyed then it will unfortunately
+ manifest as a runtime error.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="ataspectj-itds">
+ <title>Inter-type Declarations</title>
+
+ <para>
+ Inter-type declarations are challenging to support using an annotation style. For code style aspects
+ compiled with the ajc compiler, the entire type system can be made aware of inter-type declarations (new
+ supertypes, new methods, new fields) and the completeness and correctness of it can be guaranteed.
+ Achieving this with an annotation style is hard because the source code may simply be compiled with javac
+ where the type system cannot be influenced and what is compiled must be 'pure java'.
+ </para>
+ <para>
+ AspectJ 1.5.0 introduced @DeclareParents, an attempt to offer something like that which is achievable with
+ code style declare parents and the other intertype declarations (fields, methods, constructors). However,
+ it has proved too challenging to get close to the expressiveness and capabilities of code style in this area
+ and effectively @DeclareParents is offering just a mixin strategy. The definition of mixin I am using here is that when
+ some interface I is mixed into some target type T then this means that all the methods from I are created in T and their
+ implementations are simple forwarding methods that call a delegate which that provides an implementation of I.
+ </para>
+ <para>
+ The next section covers @DeclareParents but AspectJ 1.6.4 introduces @DeclareMixin - an improved approach to defining
+ a mixin and the choice of a different name for the annotation will hopefully alleviate some of the confusion about
+ why @DeclareParents just doesn't offer the same semantics as the code style variant. Offering @DeclareMixin also gives
+ code style developers a new tool for a simple mixin whereas previously they would have avoided @DeclareParents
+ thinking what it could only do was already achievable with code style syntax.
+ </para>
+ <para>
+ The defaultImpl attribute of @DeclareParents may become deprecated if @DeclareMixin proves popular, leaving
+ @DeclareParents purely as a way to introduce a marker interface.
+ </para>
+
+
+ <sect2 id="atDeclareParents" xreflabel="atDeclareParents">
+ <title>@DeclareParents</title>
+
+ <para>
+ Consider the following aspect:
+ </para>
+
+ <programlisting><![CDATA[
+public aspect MoodIndicator {
+
+ public interface Moody {};
+
+ private Mood Moody.mood = Mood.HAPPY;
+
+ public Mood Moody.getMood() {
+ return mood;
+ }
+
+ declare parents : org.xyz..* implements Moody;
+
+ before(Moody m) : execution(* *.*(..)) && this(m) {
+ System.out.println("I'm feeling " + m.getMood());
+ }
+}
+]]></programlisting>
+
+ <para>
+ This declares an interface
+ <literal>Moody</literal>
+ , and then makes two
+ inter-type declarations on the interface - a field that is private to the
+ aspect, and a method that returns the mood. Within the body of the inter-type
+ declared method
+ <literal>getMoody</literal>
+ , the type of
+ <literal>this</literal>
+ is
+ <literal>Moody</literal>
+ (the target type of the inter-type declaration).
+ </para>
+
+ <para>Using the annotation style this aspect can be written:
+ </para>
+
+ <programlisting><![CDATA[
+@Aspect
+public class MoodIndicator {
+
+ // this interface can be outside of the aspect
+ public interface Moody {
+ Mood getMood();
+ };
+
+ // this implementation can be outside of the aspect
+ public static class MoodyImpl implements Moody {
+ private Mood mood = Mood.HAPPY;
+
+ public Mood getMood() {
+ return mood;
+ }
+ }
+
+ // the field type must be the introduced interface. It can't be a class.
+ @DeclareParents(value="org.xzy..*",defaultImpl=MoodyImpl.class)
+ private Moody implementedInterface;
+
+ @Before("execution(* *.*(..)) && this(m)")
+ void feelingMoody(Moody m) {
+ System.out.println("I'm feeling " + m.getMood());
+ }
+}
+]]></programlisting>
+
+ <para>
+ This is very similar to the mixin mechanism supported by AspectWerkz. The
+ effect of the
+ <literal>@DeclareParents</literal>
+ annotation is equivalent to
+ a declare parents statement that all types matching the type pattern implement
+ the given interface (in this case Moody).
+ Each method declared in the interface is treated as an inter-type declaration.
+ Note how this scheme operates within the constraints
+ of Java type checking and ensures that
+ <literal>this</literal>
+ has access
+ to the exact same set of members as in the code style example.
+ </para>
+
+ <para>
+ Note that it is illegal to use the @DeclareParents annotation on an aspect' field of a non-interface type.
+ The interface type is the inter-type declaration contract that dictates
+ which methods are declared on the target type.
+ </para>
+
+ <programlisting><![CDATA[
+// this type will be affected by the inter-type declaration as the type pattern matches
+package org.xyz;
+public class MoodTest {
+
+ public void test() {
+ // see here the cast to the introduced interface (required)
+ Mood mood = ((Moody)this).getMood();
+ ...
+ }
+}
+]]></programlisting>
+
+ <para>The <literal>@DeclareParents</literal> annotation can also be used without specifying
+ a <literal>defaultImpl</literal> value (for example,
+ <literal>@DeclareParents("org.xyz..*")</literal>). This is equivalent to a
+ <literal>declare parents ... implements</literal> clause, and does <emphasis>not</emphasis>
+ make any inter-type declarations for default implementation of the interface methods.
+ </para>
+
+ <para>
+ Consider the following aspect:
+ </para>
+
+ <programlisting><![CDATA[
+public aspect SerializableMarker {
+ declare parents : org.xyz..* implements Serializable;
+}
+]]></programlisting>
+
+ <para>Using the annotation style this aspect can be written:
+ </para>
+
+ <programlisting><![CDATA[
+@Aspect
+public class SerializableMarker {
+ @DeclareParents("org.xyz..*")
+ Serializable implementedInterface;
+}
+]]></programlisting>
+
+
+ <para>
+ If the interface defines one or more operations, and these are not implemented by
+ the target type, an error will be issued during weaving.
+ </para>
+
+ </sect2>
+
+ <sect2 id="atDeclareMixin" xreflabel="atDeclareMixin">
+ <title>@DeclareMixin</title>
+ <para>
+ Consider the following aspect:
+ </para>
+
+ <programlisting><![CDATA[
+public aspect MoodIndicator {
+
+ public interface Moody {};
+
+ private Mood Moody.mood = Mood.HAPPY;
+
+ public Mood Moody.getMood() {
+ return mood;
+ }
+
+ declare parents : org.xyz..* implements Moody;
+
+ before(Moody m) : execution(* *.*(..)) && this(m) {
+ System.out.println("I'm feeling " + m.getMood());
+ }
+}
+]]></programlisting>
+
+ <para>
+ This declares an interface <literal>Moody</literal>, and then makes two inter-type declarations on the interface
+ - a field that is private to the aspect, and a method that returns the mood. Within the body of the inter-type
+ declared method <literal>getMoody</literal>, the type of <literal>this</literal> is <literal>Moody</literal>
+ (the target type of the inter-type declaration).
+ </para>
+
+ <para>Using the annotation style this aspect can be written:
+ </para>
+
+ <programlisting><![CDATA[
+@Aspect
+public class MoodIndicator {
+
+ // this interface can be outside of the aspect
+ public interface Moody {
+ Mood getMood();
+ };
+
+ // this implementation can be outside of the aspect
+ public static class MoodyImpl implements Moody {
+ private Mood mood = Mood.HAPPY;
+
+ public Mood getMood() {
+ return mood;
+ }
+ }
+
+ // The DeclareMixin annotation is attached to a factory method that can return instances of the delegate
+ // which offers an implementation of the mixin interface. The interface that is mixed in is the
+ // return type of the method.
+ @DeclareMixin("org.xyz..*")
+ public static Moody createMoodyImplementation() {
+ return new MoodyImpl();
+ }
+
+ @Before("execution(* *.*(..)) && this(m)")
+ void feelingMoody(Moody m) {
+ System.out.println("I'm feeling " + m.getMood());
+ }
+}
+]]></programlisting>
+
+ <para>
+ Basically, the <literal>@DeclareMixin</literal> annotation is attached to a factory method. The
+ factory method specifies the interface to mixin as its return type, and calling the method should
+ create an instance of a delegate that implements the interface. This is the interface which will
+ be delegated to from any target matching the specified type pattern.
+ </para>
+
+ <para>
+ Exploiting this syntax requires the user to obey the rules of pure Java. So references to any
+ targeted type as if it were affected by the Mixin must be made through a cast, like this:
+ </para>
+
+ <programlisting><![CDATA[
+// this type will be affected by the inter-type declaration as the type pattern matches
+package org.xyz;
+public class MoodTest {
+
+ public void test() {
+ // see here the cast to the introduced interface (required)
+ Mood mood = ((Moody)this).getMood();
+ ...
+ }
+}
+]]></programlisting>
+
+ <para>
+ Sometimes the delegate instance may want to perform differently depending upon the type/instance for
+ which it is behaving as a delegate. To support this it is possible for the factory method to specify a
+ parameter. If it does, then when the factory method is called the parameter will be the object instance for
+ which a delegate should be created:
+ </para>
+ <programlisting><![CDATA[
+@Aspect
+public class Foo {
+
+ @DeclareMixin("org.xyz..*")
+ public static SomeInterface createDelegate(Object instance) {
+ return new SomeImplementation(instance);
+ }
+}
+]]></programlisting>
+
+ <para>
+ It is also possible to make the factory method non-static - and in this case it can then exploit
+ the local state in the surrounding aspect instance, but this is only supported for singleton aspects:
+ </para>
+ <programlisting><![CDATA[
+@Aspect
+public class Foo {
+ public int maxLimit=35;
+
+ @DeclareMixin("org.xyz..*")
+ public SomeInterface createDelegate(Object instance) {
+ return new SomeImplementation(instance,maxLimit);
+ }
+}
+]]></programlisting>
+
+ <para>
+ Although the interface type is usually determined purely from the return type of the factory method, it can
+ be specified in the annotation if necessary. In this example the return type of the method extends multiple
+ other interfaces and only a couple of them (I and J) should be mixed into any matching targets:
+ </para>
+ <programlisting><![CDATA[
+// interfaces is an array of interface classes that should be mixed in
+@DeclareMixin(value="org.xyz..*",interfaces={I.class,J.class})
+public static InterfaceExtendingLotsOfInterfaces createMoodyImplementation() {
+ return new MoodyImpl();
+}
+]]></programlisting>
+
+ <para>
+ There are clearly similarities between <literal>@DeclareMixin</literal> and <literal>@DeclareParents</literal> but
+ <literal>@DeclareMixin</literal> is not pretending to offer more than a simple mixin strategy. The flexibility in
+ being able to provide the factory method instead of requiring a no-arg constructor for the implementation also
+ enables delegate instances to make decisions based upon the type for which they are the delegate.
+ </para>
+
+ <para>
+ Any annotations defined on the interface methods are also put upon the delegate forwarding methods created in the
+ matched target type.
+ </para>
+ </sect2>
+
+ </sect1>
+
+ <sect1 id="ataspectj-declare">
+ <title>Declare statements</title>
+
+ <para>The previous section on inter-type declarations covered the case
+ of declare parents ... implements. The 1.5.0 release of AspectJ 5 does
+ not support annotation style declarations for declare parents ... extends
+ and declare soft (programs with these declarations would not in general
+ be compilable by a regular Java 5 compiler, reducing the priority of
+ their implementation). These may be supported in a future release.</para>
+
+ <para>
+ Declare annotation is also not supported in the 1.5.0 release of AspectJ 5.
+ </para>
+
+ <para>Declare precedence <emphasis>is</emphasis>
+ supported. For declare precedence, use the
+ <literal>@DeclarePrecedence</literal>
+ annotation as in the following example:
+ </para>
+
+ <programlisting><![CDATA[
+public aspect SystemArchitecture {
+ declare precedence : Security*, TransactionSupport, Persistence;
+
+ // ...
+}
+]]></programlisting>
+
+ <para>
+ can be written as:
+ </para>
+
+ <programlisting><![CDATA[
+@Aspect
+@DeclarePrecedence("Security*,org.xyz.TransactionSupport,org.xyz.Persistence")
+public class SystemArchitecture {
+ // ...
+}
+]]></programlisting>
+
+ <!--
+ note: below is not supported for now.
+ <para>
+ Declare annotation is supported via annotations on a dummy type member. If the
+ <literal>Target</literal>
+ specification of the annotation allows it, use a field,
+ otherwise declare a member of the type required by the
+ <literal>Target</literal>
+ .
+ For example:
+ </para>
+
+ <programlisting><![CDATA[
+public aspect DeclareAnnotationExamples {
+ declare annotation : org.xyz.model..* : @BusinessDomain;
+
+ declare annotation : public * BankAccount+.*(..) : @Secured(role="supervisor");
+
+ declare anotation : * DAO+.* : @Persisted;
+
+}
+]]></programlisting>
+
+ <para>can be written as...</para>
+
+ <programlisting><![CDATA[
+@Aspect
+public class DeclareAnnotationExamples {
+
+ @DeclareAnnotation("org.xyz.model..*)
+ @BusinessDomain Object modelClass;
+
+ // this example assumes that the @Secured annotation has a Target
+ // annotation with value ElementType.METHOD
+ @DeclareAnnotation("public * org.xyz.banking.BankAccount+.*(..)")
+ @Secured(role="supervisor) void bankAccountMethod();
+
+ @DeclareAnnotation("* DAO+.*")
+ @Persisted Object daoFields;
+}
+]]></programlisting>
+
+ <para>
+ <emphasis>Note: Declare annotation is not available in AspectJ 1.5 M3 and syntax may change
+ when the design and implementation is complete.</emphasis>
+ </para>
+ -->
+ <para>We also support annotation style declarations for declare warning and
+ declare error - any corresponding warnings and errors will be emitted at
+ weave time, not when the aspects containing the declarations are compiled.
+ (This is the same behaviour as when using declare warning or error with the
+ code style). Declare warning and error declarations are made by annotating
+ a string constant whose value is the message to be issued.</para>
+
+ <para>Note that the String must be a literal and not the result of the invocation
+ of a static method for example.</para>
+
+ <programlisting><![CDATA[
+declare warning : call(* javax.sql..*(..)) && !within(org.xyz.daos..*)
+ : "Only DAOs should be calling JDBC.";
+
+declare error : execution(* IFoo+.*(..)) && !within(org.foo..*)
+ : "Only foo types can implement IFoo";
+]]></programlisting>
+
+ <para>can be written as...</para>
+
+ <programlisting><![CDATA[
+@DeclareWarning("call(* javax.sql..*(..)) && !within(org.xyz.daos..*)")
+static final String aMessage = "Only DAOs should be calling JDBC.";
+
+@DeclareError("execution(* IFoo+.*(..)) && !within(org.foo..*)")
+static final String badIFooImplementors = "Only foo types can implement IFoo";
+
+// the following is not valid since the message is not a String literal
+@DeclareError("execution(* IFoo+.*(..)) && !within(org.foo..*)")
+static final String badIFooImplementorsCorrupted = getMessage();
+static String getMessage() {
+ return "Only foo types can implement IFoo " + System.currentTimeMillis();
+}
+]]></programlisting>
+
+ </sect1>
+
+ <sect1 id="ataspectj-aspectof">
+ <title>aspectOf() and hasAspect() methods</title>
+
+ <para>A central part of AspectJ's programming model is that aspects
+ written using the code style and compiled using ajc support
+ <literal>aspectOf</literal>
+ and
+ <literal>hasAspect</literal>
+ static
+ methods. When developing an aspect using the annotation style and compiling
+ using a regular Java 5 compiler, these methods will not be visible to the
+ compiler and will result in a compilation error if another part of the
+ program tries to call them.
+ </para>
+
+ <para>To provide equivalent support for AspectJ applications compiled with
+ a standard Java 5 compiler, AspectJ 5 defines the
+ <literal>Aspects</literal>
+ utility class:
+ </para>
+
+ <programlisting><![CDATA[
+public class Aspects {
+
+ /* variation used for singleton, percflow, percflowbelow */
+ static<T> public static T aspectOf(T aspectType) {...}
+
+ /* variation used for perthis, pertarget */
+ static<T> public static T aspectOf(T aspectType, Object forObject) {...}
+
+ /* variation used for pertypewithin */
+ static<T> public static T aspectOf(T aspectType, Class forType) {...}
+
+ /* variation used for singleton, percflow, percflowbelow */
+ public static boolean hasAspect(Object anAspect) {...}
+
+ /* variation used for perthis, pertarget */
+ public static boolean hasAspect(Object anAspect, Object forObject) {...}
+
+ /* variation used for pertypewithin */
+ public static boolean hasAspect(Object anAspect, Class forType) {...}
+}
+]]></programlisting>
+
+ <!-- TODO AV - stuff below is not done -->
+ <!--
+ <para>When the AspectJ weaver sees calls to these methods, it will convert
+ them into the most efficient form possible (to get performance equivalent
+ to a direct <literal>MyAspect.aspectOf()</literal> call).</para>
+ -->
+ </sect1>
+</chapter>
+
+