diff options
Diffstat (limited to 'docs/adk15notebook/ataspectj.xml')
-rw-r--r-- | docs/adk15notebook/ataspectj.xml | 1144 |
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() && 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> + + |