| <html><head> | |
| <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> | |
| <title>Inter-type Declarations</title><link rel="stylesheet" href="aspectj-docs.css" type="text/css"><meta name="generator" content="DocBook XSL Stylesheets V1.44"><link rel="home" href="index.html" title="The AspectJTM 5 Development Kit Developer's Notebook"><link rel="up" href="ataspectj.html" title="Chapter 9. An Annotation Based Development Style"><link rel="previous" href="ataspectj-pcadvice.html" title="Pointcuts and Advice"><link rel="next" href="ataspectj-declare.html" title="Declare statements"></head><body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF"><div class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="3" align="center">Inter-type Declarations</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="ataspectj-pcadvice.html">Prev</a> </td><th width="60%" align="center">Chapter 9. An Annotation Based Development Style</th><td width="20%" align="right"> <a accesskey="n" href="ataspectj-declare.html">Next</a></td></tr></table><hr></div><div class="sect1"><a name="ataspectj-itds"></a><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="ataspectj-itds"></a>Inter-type Declarations</h2></div></div><p> | |
| 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'. | |
| </p><p> | |
| 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. | |
| </p><p> | |
| 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. | |
| </p><p> | |
| The defaultImpl attribute of @DeclareParents may become deprecated if @DeclareMixin proves popular, leaving | |
| @DeclareParents purely as a way to introduce a marker interface. | |
| </p><div class="sect2"><a name="atDeclareParents"></a><div class="titlepage"><div><h3 class="title"><a name="atDeclareParents"></a>@DeclareParents</h3></div></div><p> | |
| Consider the following aspect: | |
| </p><pre class="programlisting"> | |
| 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()); | |
| } | |
| } | |
| </pre><p> | |
| This declares an interface | |
| <tt>Moody</tt> | |
| , 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 | |
| <tt>getMoody</tt> | |
| , the type of | |
| <tt>this</tt> | |
| is | |
| <tt>Moody</tt> | |
| (the target type of the inter-type declaration). | |
| </p><p>Using the annotation style this aspect can be written: | |
| </p><pre class="programlisting"> | |
| @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()); | |
| } | |
| } | |
| </pre><p> | |
| This is very similar to the mixin mechanism supported by AspectWerkz. The | |
| effect of the | |
| <tt>@DeclareParents</tt> | |
| 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 | |
| <tt>this</tt> | |
| has access | |
| to the exact same set of members as in the code style example. | |
| </p><p> | |
| 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. | |
| </p><pre class="programlisting"> | |
| // 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(); | |
| ... | |
| } | |
| } | |
| </pre><p>The <tt>@DeclareParents</tt> annotation can also be used without specifying | |
| a <tt>defaultImpl</tt> value (for example, | |
| <tt>@DeclareParents("org.xyz..*")</tt>). This is equivalent to a | |
| <tt>declare parents ... implements</tt> clause, and does <span class="emphasis"><i>not</i></span> | |
| make any inter-type declarations for default implementation of the interface methods. | |
| </p><p> | |
| Consider the following aspect: | |
| </p><pre class="programlisting"> | |
| public aspect SerializableMarker { | |
| declare parents : org.xyz..* implements Serializable; | |
| } | |
| </pre><p>Using the annotation style this aspect can be written: | |
| </p><pre class="programlisting"> | |
| @Aspect | |
| public class SerializableMarker { | |
| @DeclareParents("org.xyz..*") | |
| Serializable implementedInterface; | |
| } | |
| </pre><p> | |
| If the interface defines one or more operations, and these are not implemented by | |
| the target type, an error will be issued during weaving. | |
| </p></div><div class="sect2"><a name="atDeclareMixin"></a><div class="titlepage"><div><h3 class="title"><a name="atDeclareMixin"></a>@DeclareMixin</h3></div></div><p> | |
| Consider the following aspect: | |
| </p><pre class="programlisting"> | |
| 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()); | |
| } | |
| } | |
| </pre><p> | |
| This declares an interface <tt>Moody</tt>, 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 <tt>getMoody</tt>, the type of <tt>this</tt> is <tt>Moody</tt> | |
| (the target type of the inter-type declaration). | |
| </p><p>Using the annotation style this aspect can be written: | |
| </p><pre class="programlisting"> | |
| @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()); | |
| } | |
| } | |
| </pre><p> | |
| Basically, the <tt>@DeclareMixin</tt> 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. | |
| </p><p> | |
| 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: | |
| </p><pre class="programlisting"> | |
| // 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(); | |
| ... | |
| } | |
| } | |
| </pre><p> | |
| 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: | |
| </p><pre class="programlisting"> | |
| @Aspect | |
| public class Foo { | |
| @DeclareMixin("org.xyz..*") | |
| public static SomeInterface createDelegate(Object instance) { | |
| return new SomeImplementation(instance); | |
| } | |
| } | |
| </pre><p> | |
| 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: | |
| </p><pre class="programlisting"> | |
| @Aspect | |
| public class Foo { | |
| public int maxLimit=35; | |
| @DeclareMixin("org.xyz..*") | |
| public SomeInterface createDelegate(Object instance) { | |
| return new SomeImplementation(instance,maxLimit); | |
| } | |
| } | |
| </pre><p> | |
| 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: | |
| </p><pre class="programlisting"> | |
| // 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(); | |
| } | |
| </pre><p> | |
| There are clearly similarities between <tt>@DeclareMixin</tt> and <tt>@DeclareParents</tt> but | |
| <tt>@DeclareMixin</tt> 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. | |
| </p><p> | |
| Any annotations defined on the interface methods are also put upon the delegate forwarding methods created in the | |
| matched target type. | |
| </p></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="ataspectj-pcadvice.html">Prev</a> </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right"> <a accesskey="n" href="ataspectj-declare.html">Next</a></td></tr><tr><td width="40%" align="left">Pointcuts and Advice </td><td width="20%" align="center"><a accesskey="u" href="ataspectj.html">Up</a></td><td width="40%" align="right"> Declare statements</td></tr></table></div></body></html> |