<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> |