<html><head> | |
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> | |
<title>Generics in AspectJ 5</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="generics.html" title="Chapter 3. Generics"><link rel="previous" href="generics.html" title="Chapter 3. Generics"><link rel="next" href="autoboxing.html" title="Chapter 4. Autoboxing and Unboxing"></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">Generics in AspectJ 5</th></tr><tr><td width="20%" align="left"><a accesskey="p" href="generics.html">Prev</a> </td><th width="60%" align="center">Chapter 3. Generics</th><td width="20%" align="right"> <a accesskey="n" href="autoboxing.html">Next</a></td></tr></table><hr></div><div class="sect1"><a name="generics-inAspectJ5"></a><div class="titlepage"><div><h2 class="title" style="clear: both"><a name="generics-inAspectJ5"></a>Generics in AspectJ 5</h2></div></div><p> | |
AspectJ 5 provides full support for all of the Java 5 language features, including generics. Any legal Java 5 program is a | |
legal AspectJ 5 progam. In addition, AspectJ 5 provides support for generic and parameterized types in pointcuts, inter-type | |
declarations, and declare statements. Parameterized types may freely be used within aspect members, and support is | |
also provided for generic <span class="emphasis"><i>abstract</i></span> aspects. | |
</p><div class="sect2"><a name="matching-generic-and-parameterized-types-in-pointcut-expressions"></a><div class="titlepage"><div><h3 class="title"><a name="matching-generic-and-parameterized-types-in-pointcut-expressions"></a>Matching generic and parameterized types in pointcut expressions</h3></div></div><p> | |
The simplest way to work with generic and parameterized types in pointcut expressions and type patterns | |
is simply to use the raw type name. For example, the type pattern <tt>List</tt> will match | |
the generic type <tt>List<E></tt> and any parameterization of that type | |
(<tt>List<String>, List<?>, List<? extends Number></tt> and so on. This | |
ensures that pointcuts written in existing code that is not generics-aware will continue to work as | |
expected in AspectJ 5. It is also the recommended way to match against generic and parameterized types | |
in AspectJ 5 unless you explicitly wish to narrow matches to certain parameterizations of a generic type. | |
</p><p>Generic methods and constructors, and members defined in generic types, may use type variables | |
as part of their signature. For example:</p><pre class="programlisting"> | |
public class Utils { | |
/** static generic method */ | |
static <T> T first(List<T> ts) { ... } | |
/** instance generic method */ | |
<T extends Number> T max(T t1, T t2) { ... } | |
} | |
public class G<T> { | |
// field with parameterized type | |
T myData; | |
// method with parameterized return type | |
public List<T> getAllDataItems() {...} | |
} | |
</pre><p> | |
AspectJ 5 does not allow the use of type variables in pointcut expressions and type patterns. Instead, members that | |
use type parameters as part of their signature are matched by their <span class="emphasis"><i>erasure</i></span>. Java 5 defines the | |
rules for determing the erasure of a type as follows. | |
</p><p>Let <tt>|T|</tt> represent the erasure of some type <tt>T</tt>. Then:</p><table class="simplelist" border="0" summary="Simple list"><tr><td>The erasure of a parameterized type <tt>T<T1,...,Tn></tt> is <tt>|T|</tt>. | |
For example, the erasure of <tt>List<String></tt> is <tt>List</tt>.</td></tr><tr><td>The erasure of a nested type <tt>T.C</tt> is <tt>|T|.C</tt>. For example, | |
the erasure of the nested type <tt>Foo<T>.Bar</tt> is <tt>Foo.Bar</tt>.</td></tr><tr><td>The erasure of an array type <tt>T[]</tt> is <tt>|T|[]</tt>. For example, | |
the erasure of <tt>List<String>[]</tt> is <tt>List[]</tt>.</td></tr><tr><td>The erasure of a type variable is its leftmost bound. For example, the erasure of a | |
type variable <tt>P</tt> is <tt>Object</tt>, and the erasure of a type | |
variable <tt>N extends Number</tt> is <tt>Number</tt>.</td></tr><tr><td>The erasure of every other type is the type itself</td></tr></table><p>Applying these rules to the earlier examples, we find that the methods defined in <tt>Utils</tt> | |
can be matched by a signature pattern matching <tt>static Object Utils.first(List)</tt> and | |
<tt>Number Utils.max(Number, Number)</tt> respectively. The members of the generic type | |
<tt>G</tt> can be matched by a signature pattern matching <tt>Object G.myData</tt> and | |
<tt>public List G.getAllDataItems()</tt> respectively.</p><div class="sect3"><a name="d0e2217"></a><div class="titlepage"><div><h4 class="title"><a name="d0e2217"></a>Restricting matching using parameterized types</h4></div></div><p>Pointcut matching can be further restricted to match only given parameterizations of parameter types (methods and constructors), return | |
types (methods) and field types (fields). This is achieved by specifying a parameterized type pattern at the appropriate point | |
in the signature pattern. For example, given the class <tt>Foo</tt>:</p><pre class="programlisting"> | |
public class Foo { | |
List<String> myStrings; | |
List<Float> myFloats; | |
public List<String> getStrings() { return myStrings; } | |
public List<Float> getFloats() { return myFloats; } | |
public void addStrings(List<String> evenMoreStrings) { | |
myStrings.addAll(evenMoreStrings); | |
} | |
} | |
</pre><p>Then a <tt>get</tt> join point for the field <tt>myStrings</tt> can be matched by the | |
pointcut <tt>get(List Foo.myStrings)</tt> and by the pointcut <tt>get(List<String> Foo.myStrings)</tt>, | |
but <span class="emphasis"><i>not</i></span> by the pointcut <tt>get(List<Number> *)</tt>.</p><p>A <tt>get</tt> join point for the field <tt>myFloats</tt> can be matched by the | |
pointcut <tt>get(List Foo.myFloats)</tt>, the pointcut <tt>get(List<Float> *)</tt>, | |
and the pointcut <tt>get(List<Number+> *)</tt>. This last example shows how AspectJ type | |
patterns can be used to match type parameters types just like any other type. The pointcut | |
<tt>get(List<Double> *)</tt> does <span class="emphasis"><i>not</i></span> match.</p><p>The execution of the methods <tt>getStrings</tt> and <tt>getFloats</tt> can be | |
matched by the pointcut expression <tt>execution(List get*(..))</tt>, and the pointcut | |
expression <tt>execution(List<*> get*(..))</tt>, but only <tt>getStrings</tt> | |
is matched by <tt>execution(List<String> get*(..))</tt> and only <tt>getFloats</tt> | |
is matched by <tt>execution(List<Number+> get*(..))</tt></p><p>A call to the method <tt>addStrings</tt> can be matched by the pointcut expression | |
<tt>call(* addStrings(List))</tt> and by the expression <tt>call(* addStrings(List<String>))</tt>, | |
but <span class="emphasis"><i>not</i></span> by the expression <tt>call(* addStrings(List<Number>))</tt>. | |
</p><p>Remember that any type variable reference in a generic member is | |
<span class="emphasis"><i>always</i></span> matched by its erasure. Thus given the following | |
example:</p><pre class="programlisting"> | |
class G<T> { | |
List<T> foo(List<String> ls) { return null; } | |
} | |
</pre><p>The execution of <tt>foo</tt> can be matched by | |
<tt>execution(List foo(List))</tt>, | |
<tt>execution(List foo(List<String>>))</tt>, and | |
<tt>execution(* foo(List<String<))</tt>but | |
<span class="emphasis"><i>not</i></span> by <tt>execution(List<Object> foo(List<String>>)</tt> | |
since the erasure of <tt>List<T></tt> is <tt>List</tt> | |
and not <tt>List<Object></tt>. | |
</p></div><div class="sect3"><a name="d0e2350"></a><div class="titlepage"><div><h4 class="title"><a name="d0e2350"></a>Generic wildcards and signature matching</h4></div></div><p> | |
When it comes to signature matching, a type parameterized using a generic wildcard is a distinct type. | |
For example, <tt>List<?></tt> is a very different type to <tt>List<String></tt>, | |
even though a variable of type <tt>List<String></tt> can be assigned to a variable of | |
type <tt>List<?></tt>. Given the methods: | |
</p><pre class="programlisting"> | |
class C { | |
public void foo(List<? extends Number> listOfSomeNumberType) {} | |
public void bar(List<?> listOfSomeType) {} | |
public void goo(List<Double> listOfDoubles) {} | |
} | |
</pre><div class="variablelist"><dl><dt><a name="d0e2371"></a><span class="term">execution(* C.*(List))</span></dt><dd><p><a name="d0e2374"></a>Matches an execution join point for any of the three methods. | |
</p></dd><dt><a name="d0e2377"></a><span class="term">execution(* C.*(List<? extends Number>))</span></dt><dd><p><a name="d0e2380"></a>matches only the | |
execution of <tt>foo</tt>, and <span class="emphasis"><i>not</i></span> the execution | |
of <tt>goo</tt> since <tt>List<? extends Number></tt> and | |
<tt>List<Double></tt> are distinct types. | |
</p></dd><dt><a name="d0e2398"></a><span class="term">execution(* C.*(List<?>))</span></dt><dd><p><a name="d0e2401"></a>matches only the execution of <tt>bar</tt>. | |
</p></dd><dt><a name="d0e2407"></a><span class="term">execution(* C.*(List<? extends Object+>))</span></dt><dd><p><a name="d0e2410"></a>matches both the execution of <tt>foo</tt> and the execution of <tt>bar</tt> | |
since the upper bound of <tt>List<?></tt> is implicitly <tt>Object</tt>. | |
</p></dd></dl></div></div><div class="sect3"><a name="d0e2425"></a><div class="titlepage"><div><h4 class="title"><a name="d0e2425"></a>Treatment of bridge methods</h4></div></div><p>Under certain circumstances a Java 5 compiler is required to create <span class="emphasis"><i>bridge | |
methods</i></span> that support the compilation of programs using raw types. Consider the types</p><pre class="programlisting"> | |
class Generic<T> { | |
public T foo(T someObject) { | |
return someObject; | |
} | |
} | |
class SubGeneric<N extends Number> extends Generic<N> { | |
public N foo(N someNumber) { | |
return someNumber; | |
} | |
} | |
</pre><p>The class <tt>SubGeneric</tt> extends <tt>Generic</tt> | |
and overrides the method <tt>foo</tt>. Since the upper bound of the type variable | |
<tt>N</tt> in <tt>SubGeneric</tt> is different to the upper bound of | |
the type variable <tt>T</tt> in <tt>Generic</tt>, the method <tt>foo</tt> | |
in <tt>SubGeneric</tt> has a different erasure to the method <tt>foo</tt> | |
in <tt>Generic</tt>. This is an example of a case where a Java 5 compiler will create | |
a <span class="emphasis"><i>bridge method</i></span> in <tt>SubGeneric</tt>. Although you never see it, | |
the bridge method will look something like this:</p><pre class="programlisting"> | |
public Object foo(Object arg) { | |
Number n = (Number) arg; // "bridge" to the signature defined in this type | |
return foo(n); | |
} | |
</pre><p>Bridge methods are synthetic artefacts generated as a result of a particular compilation strategy and | |
have no execution join points in AspectJ 5. So the pointcut <tt>execution(Object SubGeneric.foo(Object))</tt> | |
does not match anything. (The pointcut <tt>execution(Object Generic.foo(Object))</tt> matches the | |
execution of <tt>foo</tt> in both <tt>Generic</tt> and <tt>SubGeneric</tt> since | |
both are implementations of <tt>Generic.foo</tt>). | |
</p><p>It <span class="emphasis"><i>is</i></span> possible to <span class="emphasis"><i>call</i></span> a bridge method as the following short | |
code snippet demonstrates. Such a call <span class="emphasis"><i>does</i></span> result in a call join point for the call to | |
the method. | |
</p><pre class="programlisting"> | |
SubGeneric rawType = new SubGeneric(); | |
rawType.foo("hi"); // call to bridge method (will result in a runtime failure in this case) | |
Object n = new Integer(5); | |
rawType.foo(n); // call to bridge method that would succeed at runtime | |
</pre></div><div class="sect3"><a name="d0e2512"></a><div class="titlepage"><div><h4 class="title"><a name="d0e2512"></a>Runtime type matching with this(), target() and args()</h4></div></div><p>The <tt>this()</tt>, <tt>target()</tt>, and | |
<tt>args()</tt> pointcut expressions all match based on the runtime | |
type of their arguments. Because Java 5 implements generics using erasure, it is not | |
possible to ask at runtime whether an object is an instance of a given parameterization of a type | |
(only whether or not it is an instance of the erasure of that parameterized type). Therefore | |
AspectJ 5 does not support the use of parameterized types with the <tt>this()</tt> and | |
<tt>target()</tt> pointcuts. Parameterized types may however be used in conjunction with | |
<tt>args()</tt>. Consider the following class | |
</p><pre class="programlisting"> | |
public class C { | |
public void foo(List<String> listOfStrings) {} | |
public void bar(List<Double> listOfDoubles) {} | |
public void goo(List<? extends Number> listOfSomeNumberType) {} | |
} | |
</pre><div class="variablelist"><dl><dt><a name="d0e2539"></a><span class="term">args(List)</span></dt><dd><p><a name="d0e2542"></a>will match an execution or call join point for any of | |
these methods | |
</p></dd><dt><a name="d0e2545"></a><span class="term">args(List<String>)</span></dt><dd><p><a name="d0e2548"></a>will match an execution | |
or call join point for <tt>foo</tt>. | |
</p></dd><dt><a name="d0e2554"></a><span class="term">args(List<Double>)</span></dt><dd><p><a name="d0e2557"></a>matches an execution or call join point for <tt>bar</tt>, and <span class="emphasis"><i>may</i></span> match | |
at an execution or call join point for <tt>goo</tt> since it is legitimate to pass an | |
object of type <tt>List<Double></tt> to a method expecting a <tt>List<? extends Number></tt>. | |
</p><p> | |
In this situation a runtime test would normally be applied to ascertain whether or not the argument | |
was indeed an instance of the required type. However, in the case of parameterized types such a test is not | |
possible and therefore AspectJ 5 considers this a match, but issues an <span class="emphasis"><i>unchecked</i></span> warning. | |
For example, compiling the aspect <tt>A</tt> below with the class <tt>C</tt> produces the | |
compilation warning: "unchecked match of List<Double> with List<? extends Number> when argument is | |
an instance of List at join point method-execution(void C.goo(List<? extends Number>)) [Xlint:uncheckedArgument]"; | |
</p></dd></dl></div><pre class="programlisting"> | |
public aspect A { | |
before(List<Double> listOfDoubles) : execution(* C.*(..)) && args(listOfDoubles) { | |
for (Double d : listOfDoubles) { | |
// do something | |
} | |
} | |
} | |
</pre><p>Like all Lint messages, the <tt>uncheckedArgument</tt> warning can be | |
configured in severity from the default warning level to error or even ignore if preferred. | |
In addition, AspectJ 5 offers the annotation <tt>@SuppressAjWarnings</tt> which is | |
the AspectJ equivalent of Java's <tt>@SuppressWarnings</tt> annotation. If the | |
advice is annotated with <tt>@SuppressWarnings</tt> then <span class="emphasis"><i>all</i></span> | |
lint warnings issued during matching of pointcut associated with the advice will be | |
suppressed. To suppress just an <tt>uncheckedArgument</tt> warning, use the | |
annotation <tt>@SuppressWarnings("uncheckedArgument")</tt> as in the following | |
examples: | |
</p><pre class="programlisting"> | |
import org.aspectj.lang.annotation.SuppressAjWarnings | |
public aspect A { | |
@SuppressAjWarnings // will not see *any* lint warnings for this advice | |
before(List<Double> listOfDoubles) : execution(* C.*(..)) && args(listOfDoubles) { | |
for (Double d : listOfDoubles) { | |
// do something | |
} | |
} | |
@SuppressAjWarnings("uncheckedArgument") // will not see *any* lint warnings for this advice | |
before(List<Double> listOfDoubles) : execution(* C.*(..)) && args(listOfDoubles) { | |
for (Double d : listOfDoubles) { | |
// do something | |
} | |
} | |
} | |
</pre><p> | |
The safest way to deal with <tt>uncheckedArgument</tt> warnings however is to restrict the pointcut | |
to match only at those join points where the argument is guaranteed to match. This is achieved by combining | |
<tt>args</tt> with a <tt>call</tt> or <tt>execution</tt> signature matching | |
pointcut. In the following example the advice will match the execution of <tt>bar</tt> but not | |
of <tt>goo</tt> since the signature of <tt>goo</tt> is not matched by the execution pointcut | |
expression. | |
</p><pre class="programlisting"> | |
public aspect A { | |
before(List<Double> listOfDoubles) : execution(* C.*(List<Double>)) && args(listOfDoubles) { | |
for (Double d : listOfDoubles) { | |
// do something | |
} | |
} | |
} | |
</pre><p>Generic wildcards can be used in args type patterns, and matching follows regular Java 5 assignability rules. For | |
example, <tt>args(List<?>)</tt> will match a list argument of any type, and | |
<tt>args(List<? extends Number>)</tt> will match an argument of type | |
<tt>List<Number>, List<Double>, List<Float></tt> and so on. Where a match cannot be | |
fully statically determined, the compiler will once more issue an <tt>uncheckedArgument</tt> warning. | |
</p><p>Consider the following program:</p><pre class="programlisting"> | |
public class C { | |
public static void main(String[] args) { | |
C c = new C(); | |
List<String> ls = new ArrayList<String>(); | |
List<Double> ld = new ArrayList<Double>(); | |
c.foo("hi"); | |
c.foo(ls); | |
c.foo(ld); | |
} | |
public void foo(Object anObject) {} | |
} | |
aspect A { | |
before(List<? extends Number> aListOfSomeNumberType) | |
: call(* foo(..)) && args(aListOfSomeNumberType) { | |
// process list... | |
} | |
} | |
</pre><p>From the signature of <tt>foo</tt> all we know is that the runtime argument will be an instance of | |
<tt>Object</tt>.Compiling this program gives the unchecked argument warning: | |
"unchecked match of List<? extends Number> with List when argument is | |
an instance of List at join point method-execution(void C.foo(Object)) [Xlint:uncheckedArgument]". | |
The advice will not execute at the call join point for <tt>c.foo("hi")</tt> since <tt>String</tt> | |
is not an instance of <tt>List</tt>. The advice <span class="emphasis"><i>will</i></span> execute at the call join points | |
for <tt>c.foo(ls)</tt> and <tt>c.foo(ld)</tt> since in both cases the argument is an instance of | |
<tt>List</tt>. | |
</p><p>Combine a wildcard argument type with a signature pattern to avoid unchecked argument matches. In the example | |
below we use the signature pattern <tt>List<Number+></tt> to match a call to any method taking | |
a <tt>List<Number>, List<Double>, List<Float></tt> and so on. In addition the | |
signature pattern <tt>List<? extends Number+></tt> can be used to match a call to a method | |
declared to take a <tt>List<? extends Number></tt>, <tt>List<? extends Double></tt> | |
and so on. Taken together, these restrict matching to only | |
those join points at which the argument is guaranteed to be an instance of <tt>List<? extends Number></tt>.</p><pre class="programlisting"> | |
aspect A { | |
before(List<? extends Number> aListOfSomeNumberType) | |
: (call(* foo(List<Number+>)) || call(* foo(List<? extends Number+>))) | |
&& args(aListOfSomeNumberType) { | |
// process list... | |
} | |
} | |
</pre></div><div class="sect3"><a name="d0e2708"></a><div class="titlepage"><div><h4 class="title"><a name="d0e2708"></a>Binding return values in after returning advice</h4></div></div><p> | |
After returning advice can be used to bind the return value from a matched join point. AspectJ 5 supports the use of | |
a parameterized type in the returning clause, with matching following the same rules as described for args. For | |
example, the following aspect matches the execution of any method returning a <tt>List</tt>, and makes | |
the returned list available to the body of the advice. | |
</p><pre class="programlisting"> | |
public aspect A { | |
pointcut executionOfAnyMethodReturningAList() : execution(List *(..)); | |
after() returning(List<?> listOfSomeType) : executionOfAnyMethodReturningAList() { | |
for (Object element : listOfSomeType) { | |
// process element... | |
} | |
} | |
} | |
</pre><p>The pointcut uses the raw type pattern <tt>List</tt>, and hence it | |
matches methods returning any kind of list (<tt>List<String>, List<Double></tt>, | |
and so on). We've chosen to bind the returned list as the parameterized type | |
<tt>List<?></tt> in the advice since Java's type checking will now ensure | |
that we only perform safe operations on the list.</p><p>Given the class</p><pre class="programlisting"> | |
public class C { | |
public List<String> foo(List<String> listOfStrings) {...} | |
public List<Double> bar(List<Double> listOfDoubles) {...} | |
public List<? extends Number> goo(List<? extends Number> listOfSomeNumberType) {...} | |
} | |
</pre><p>The advice in the aspect below will run after the execution of <tt>bar</tt> | |
and bind the return value. It will also run after the execution of <tt>goo</tt> and | |
bind the return value, but gives an <tt>uncheckedArgument</tt> warning during | |
compilation. It does <span class="emphasis"><i>not</i></span> run after the execution of <tt>foo</tt>. | |
</p><pre class="programlisting"> | |
public aspect Returning { | |
after() returning(List<Double> listOfDoubles) : execution(* C.*(..)) { | |
for(Double d : listOfDoubles) { | |
// process double... | |
} | |
} | |
} | |
</pre><p>As with <tt>args</tt> you can guarantee that after returning advice only | |
executes on lists <span class="emphasis"><i>statically determinable</i></span> to be of the right | |
type by specifying a return type pattern in the associated pointcut. The | |
<tt>@SuppressAjWarnings</tt> annotation can also be used if desired.</p></div><div class="sect3"><a name="d0e2764"></a><div class="titlepage"><div><h4 class="title"><a name="d0e2764"></a>Declaring pointcuts inside generic types</h4></div></div><p>Pointcuts can be declared in both classes and aspects. A pointcut declared in a generic | |
type may use the type variables of the type in which it is declared. All references to | |
a pointcut declared in a generic type from outside of that type must be via a parameterized type reference, | |
and not a raw type reference.</p><p>Consider the generic type <tt>Generic</tt> with a pointcut <tt>foo</tt>: | |
</p><pre class="programlisting"> | |
public class Generic<T> { | |
/** | |
* matches the execution of any implementation of a method defined for T | |
*/ | |
public pointcut foo() : execution(* T.*(..)); | |
} | |
</pre><p>Such a pointcut must be refered to using a parameterized reference as shown | |
below.</p><pre class="programlisting"> | |
public aspect A { | |
// runs before the execution of any implementation of a method defined for MyClass | |
before() : Generic<MyClass>.foo() { | |
// ... | |
} | |
// runs before the execution of any implementation of a method defined for YourClass | |
before() : Generic<YourClass>.foo() { | |
// ... | |
} | |
// results in a compilation error - raw type reference | |
before() : Generic.foo() { } | |
} | |
</pre></div></div><div class="sect2"><a name="inter-type-declarations"></a><div class="titlepage"><div><h3 class="title"><a name="inter-type-declarations"></a>Inter-type Declarations</h3></div></div><p> | |
AspectJ 5 supports the inter-type declaration of generic methods, and of members on | |
generic types. For generic methods, the syntax is exactly as for a regular method | |
declaration, with the addition of the target type specification: | |
</p><div class="variablelist"><dl><dt><a name="d0e2790"></a><span class="term"><T extends Number> T Utils.max(T first, T second) {...}</span></dt><dd><p><a name="d0e2793"></a>Declares a generic instance method <tt>max</tt> on the class <tt>Util</tt>. | |
The <tt>max</tt> method takes two arguments, <tt>first</tt> and <tt>second</tt> which must | |
both be of the same type (and that type must be Number or a subtype of Number) and returns an instance | |
of that type. | |
</p></dd><dt><a name="d0e2811"></a><span class="term">static <E> E Utils.first(List<E> elements) {...}</span></dt><dd><p><a name="d0e2814"></a>Declares a static generic method <tt>first</tt> on the class <tt>Util</tt>. | |
The <tt>first</tt> method takes a list of elements of some type, and returns an instance | |
of that type. | |
</p></dd><dt><a name="d0e2826"></a><span class="term"><T> Sorter.new(List<T> elements,Comparator<? super T> comparator) {...}</span></dt><dd><p><a name="d0e2829"></a>Declares a constructor on the class <tt>Sorter</tt>. | |
The constructor takes a list of elements of some type, and a comparator that can compare instances | |
of the element type. | |
</p></dd></dl></div><p> | |
A generic type may be the target of an inter-type declaration, used either in its raw form or with | |
type parameters specified. If type parameters are specified, then the number of type parameters given | |
must match the number of type parameters in | |
the generic type declaration. Type parameter <span class="emphasis"><i>names</i></span> do not have to match. | |
For example, given the generic type <tt>Foo<T,S extends Number></tt> then: | |
</p><div class="variablelist"><dl><dt><a name="d0e2844"></a><span class="term">String Foo.getName() {...}</span></dt><dd><p><a name="d0e2847"></a>Declares a <tt>getName</tt> method on behalf of the type <tt>Foo</tt>. It is | |
not possible to refer to the type parameters of Foo in such a declaration. | |
</p></dd><dt><a name="d0e2856"></a><span class="term">public R Foo<Q, R>.getMagnitude() {...}</span></dt><dd><p><a name="d0e2859"></a>Declares a method <tt>getMagnitude</tt> on the generic class <tt>Foo</tt>. | |
The method returns an instance of the type substituted for the second type parameter in an invocation | |
of <tt>Foo</tt> If <tt>Foo</tt> is declared as | |
<tt>Foo<T,N extends Number> {...}</tt> then this inter-type declaration is | |
equivalent to the declaration of a method <tt>public N getMagnitude()</tt> | |
within the body of <tt>Foo</tt>. | |
</p></dd><dt><a name="d0e2883"></a><span class="term">R Foo<Q, R extends Number>.getMagnitude() {...}</span></dt><dd><p><a name="d0e2886"></a>Results in a compilation error since a bounds specification is not allowed in this | |
form of an inter-type declaration (the bounds are determined from the declaration of the | |
target type). | |
</p></dd></dl></div><p>A parameterized type may not be the target of an inter-type declaration. This is because | |
there is only one type (the generic type) regardless of how many different invocations (parameterizations) of | |
that generic type are made in a program. Therefore it does not make sense to try and declare a member | |
on behalf of (say) <tt>Bar<String></tt>, you can only declare members on the generic | |
type <tt>Bar<T></tt>. | |
</p></div><div class="sect2"><a name="declare-parents"></a><div class="titlepage"><div><h3 class="title"><a name="declare-parents"></a>Declare Parents</h3></div></div><p>Both generic and parameterized types can be used as the parent type in a <tt>declare parents</tt> | |
statement (as long as the resulting type hierarchy would be well-formed in accordance with Java's sub-typing | |
rules). Generic types may also be used as the target type of a <tt>declare parents</tt> statement.</p><div class="variablelist"><dl><dt><a name="d0e2909"></a><span class="term">declare parents: Foo implements List<String></span></dt><dd><p><a name="d0e2912"></a>The <tt>Foo</tt> type implements the <tt>List<String></tt> interface. If | |
<tt>Foo</tt> already implements some other parameterization of the <tt>List</tt> | |
interface (for example, <tt>List<Integer></tt> then a compilation error will result since a | |
type cannot implement multiple parameterizations of the same generic interface type. | |
</p></dd></dl></div></div><div class="sect2"><a name="declare-soft"></a><div class="titlepage"><div><h3 class="title"><a name="declare-soft"></a>Declare Soft</h3></div></div><p>It is an error to use a generic or parameterized type as the softened exception type in a declare soft statement. Java 5 does | |
not permit a generic class to be a direct or indirect subtype of <tt>Throwable</tt> (JLS 8.1.2).</p></div><div class="sect2"><a name="generic-aspects"></a><div class="titlepage"><div><h3 class="title"><a name="generic-aspects"></a>Generic Aspects</h3></div></div><p> | |
AspectJ 5 allows an <span class="emphasis"><i>abstract</i></span> aspect to be declared as a generic type. Any concrete | |
aspect extending a generic abstract aspect must extend a parameterized version of the abstract aspect. | |
Wildcards are not permitted in this parameterization. | |
</p><p>Given the aspect declaration:</p><pre class="programlisting"> | |
public abstract aspect ParentChildRelationship<P,C> { | |
... | |
} | |
</pre><p>then</p><div class="variablelist"><dl><dt><a name="d0e2953"></a><span class="term">public aspect FilesInFolders extends ParentChildRelationship<Folder,File> {...</span></dt><dd><p><a name="d0e2956"></a>declares a concrete sub-aspect, <tt>FilesInFolders</tt> which extends the | |
parameterized abstract aspect <tt>ParentChildRelationship<Folder,File></tt>. | |
</p></dd><dt><a name="d0e2965"></a><span class="term">public aspect FilesInFolders extends ParentChildRelationship {...</span></dt><dd><p><a name="d0e2968"></a>results in a compilation error since the <tt>ParentChildRelationship</tt> aspect must | |
be fully parameterized. | |
</p></dd><dt><a name="d0e2974"></a><span class="term">public aspect ThingsInFolders<T> extends ParentChildRelationship<Folder,T></span></dt><dd><p><a name="d0e2977"></a>results in a compilation error since concrete aspects may not have type parameters. | |
</p></dd><dt><a name="d0e2980"></a><span class="term">public abstract aspect ThingsInFolders<T> extends ParentChildRelationship<Folder,T></span></dt><dd><p><a name="d0e2983"></a>declares a sub-aspect of <tt>ParentChildRelationship</tt> in which <tt>Folder</tt> | |
plays the role of parent (is bound to the type variable <tt>P</tt>). | |
</p></dd></dl></div><p>The type parameter variables from a generic aspect declaration may be used in place of a type within any | |
member of the aspect, <span class="emphasis"><i>except for within inter-type declarations</i></span>. | |
For example, we can declare a <tt>ParentChildRelationship</tt> aspect to | |
manage the bi-directional relationship between parent and child nodes as follows: | |
</p><pre class="programlisting"> | |
/** | |
* a generic aspect, we've used descriptive role names for the type variables | |
* (Parent and Child) but you could use anything of course | |
*/ | |
public abstract aspect ParentChildRelationship<Parent,Child> { | |
/** generic interface implemented by parents */ | |
interface ParentHasChildren<C extends ChildHasParent>{ | |
List<C> getChildren(); | |
void addChild(C child); | |
void removeChild(C child); | |
} | |
/** generic interface implemented by children */ | |
interface ChildHasParent<P extends ParentHasChildren>{ | |
P getParent(); | |
void setParent(P parent); | |
} | |
/** ensure the parent type implements ParentHasChildren<child type> */ | |
declare parents: Parent implements ParentHasChildren<Child>; | |
/** ensure the child type implements ChildHasParent<parent type> */ | |
declare parents: Child implements ChildHasParent<Parent>; | |
// Inter-type declarations made on the *generic* interface types to provide | |
// default implementations. | |
/** list of children maintained by parent */ | |
private List<C> ParentHasChildren<C>.children = new ArrayList<C>(); | |
/** reference to parent maintained by child */ | |
private P ChildHasParent<P>.parent; | |
/** Default implementation of getChildren for the generic type ParentHasChildren */ | |
public List<C> ParentHasChildren<C>.getChildren() { | |
return Collections.unmodifiableList(children); | |
} | |
/** Default implementation of getParent for the generic type ChildHasParent */ | |
public P ChildHasParent<P>.getParent() { | |
return parent; | |
} | |
/** | |
* Default implementation of addChild, ensures that parent of child is | |
* also updated. | |
*/ | |
public void ParentHasChildren<C>.addChild(C child) { | |
if (child.parent != null) { | |
child.parent.removeChild(child); | |
} | |
children.add(child); | |
child.parent = this; | |
} | |
/** | |
* Default implementation of removeChild, ensures that parent of | |
* child is also updated. | |
*/ | |
public void ParentHasChildren<C>.removeChild(C child) { | |
if (children.remove(child)) { | |
child.parent = null; | |
} | |
} | |
/** | |
* Default implementation of setParent for the generic type ChildHasParent. | |
* Ensures that this child is added to the children of the parent too. | |
*/ | |
public void ChildHasParent<P>.setParent(P parent) { | |
parent.addChild(this); | |
} | |
/** | |
* Matches at an addChild join point for the parent type P and child type C | |
*/ | |
public pointcut addingChild(Parent p, Child c) : | |
execution(* ParentHasChildren.addChild(ChildHasParent)) && this(p) && args(c); | |
/** | |
* Matches at a removeChild join point for the parent type P and child type C | |
*/ | |
public pointcut removingChild(Parent p, Child c) : | |
execution(* ParentHasChildren.removeChild(ChildHasParent)) && this(p) && args(c); | |
} | |
</pre><p> | |
The example aspect captures the protocol for managing a bi-directional parent-child relationship between | |
any two types playing the role of parent and child. In a compiler implementation managing an abstract syntax | |
tree (AST) in which AST nodes may contain other AST nodes we could declare the concrete aspect: | |
</p><pre class="programlisting"> | |
public aspect ASTNodeContainment extends ParentChildRelationship<ASTNode,ASTNode> { | |
before(ASTNode parent, ASTNode child) : addingChild(parent, child) { | |
... | |
} | |
} | |
</pre><p> | |
As a result of this declaration, <tt>ASTNode</tt> gains members: | |
</p><table class="simplelist" border="0" summary="Simple list"><tr><td><tt>List<ASTNode> children</tt></td></tr><tr><td><tt>ASTNode parent</tt></td></tr><tr><td><tt>List<ASTNode>getChildren()</tt></td></tr><tr><td><tt>ASTNode getParent()</tt></td></tr><tr><td><tt>void addChild(ASTNode child)</tt></td></tr><tr><td><tt>void removeChild(ASTNode child)</tt></td></tr><tr><td><tt>void setParent(ASTNode parent)</tt></td></tr></table><p> | |
In a system managing orders, we could declare the concrete aspect: | |
</p><pre class="programlisting"> | |
public aspect OrderItemsInOrders extends ParentChildRelationship<Order,OrderItem> { | |
} | |
</pre><p> | |
As a result of this declaration, <tt>Order</tt> gains members: | |
</p><table class="simplelist" border="0" summary="Simple list"><tr><td><tt>List<OrderItem> children</tt></td></tr><tr><td><tt>List<OrderItem> getChildren()</tt></td></tr><tr><td><tt>void addChild(OrderItem child)</tt></td></tr><tr><td><tt>void removeChild(OrderItem child)</tt></td></tr></table><p>and <tt>OrderItem</tt> gains members:</p><table class="simplelist" border="0" summary="Simple list"><tr><td><tt>Order parent</tt></td></tr><tr><td><tt>Order getParent()</tt></td></tr><tr><td><tt>void setParent(Order parent)</tt></td></tr></table><p>A second example of an abstract aspect, this time for handling exceptions in a uniform | |
manner, is shown below:</p><pre class="programlisting"> | |
abstract aspect ExceptionHandling<T extends Throwable> { | |
/** | |
* method to be implemented by sub-aspects to handle thrown exceptions | |
*/ | |
protected abstract void onException(T anException); | |
/** | |
* to be defined by sub-aspects to specify the scope of exception handling | |
*/ | |
protected abstract pointcut inExceptionHandlingScope(); | |
/** | |
* soften T within the scope of the aspect | |
*/ | |
declare soft: T : inExceptionHandlingScope(); | |
/** | |
* bind an exception thrown in scope and pass it to the handler | |
*/ | |
after() throwing (T anException) : inExceptionHandlingScope() { | |
onException(anException); | |
} | |
} | |
</pre><p>Notice how the type variable <tt>T extends Throwable</tt> allows the | |
components of the aspect to be designed to work together in a type-safe manner. The | |
following concrete sub-aspect shows how the abstract aspect might be extended to | |
handle <tt>IOExceptions</tt>.</p><pre class="programlisting"> | |
public aspect IOExceptionHandling extends ExceptionHandling<IOException>{ | |
protected pointcut inExceptionHandlingScope() : | |
call(* doIO*(..)) && within(org.xyz..*); | |
/** | |
* called whenever an IOException is thrown in scope. | |
*/ | |
protected void onException(IOException ex) { | |
System.err.println("handled exception: " + ex.getMessage()); | |
throw new MyDomainException(ex); | |
} | |
} | |
</pre></div></div><div class="navfooter"><hr><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="generics.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="autoboxing.html">Next</a></td></tr><tr><td width="40%" align="left">Chapter 3. Generics </td><td width="20%" align="center"><a accesskey="u" href="generics.html">Up</a></td><td width="40%" align="right"> Chapter 4. Autoboxing and Unboxing</td></tr></table></div></body></html> |