12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301 |
- <!--<!DOCTYPE chapter SYSTEM "file:/C:/Documents%20and%20Settings/colyer/My%20Documents/projects/aspectjdev/lib/docbook/docbook-dtd/docbookx.dtd">
- -->
- <chapter id="generics" xreflabel="Generics">
-
- <title>Generics</title>
-
- <sect1 id="generics-inJava5">
- <title>Generics in Java 5</title>
-
- <para>
- This section provides the essential information about generics in
- Java 5 needed to understand how generics are treated in AspectJ 5.
- For a full introduction to generics in Java, please see the
- documentation for the Java 5 SDK.
- </para>
-
- <sect2 id="declaring-generic-types" xreflabel="declaring-generic-types">
- <title>Declaring Generic Types</title>
-
- <para>
- A generic type is declared with one or more type parameters following the type name.
- By convention formal type parameters are named using a single letter, though this is not required.
- A simple generic list type
- (that can contain elements of any type <literal>E</literal>) could be declared:
- </para>
-
- <programlisting><![CDATA[
- interface List<E> {
- Iterator<E> iterator();
- void add(E anItem);
- E remove(E anItem);
- }
- ]]></programlisting>
-
-
- <para>
- It is important to understand that unlike template mechanisms there will only be one type, and one class file, corresponding to
- the <literal>List</literal> interface, regardless of how many different instantiations of the <literal>List</literal> interface a program
- has (each potentially providing a different value for the type parameter <literal>E</literal>). A consequence of this
- is that you cannot refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or
- initializer of a static variable.
- </para>
- <para>
- A <emphasis>parameterized type</emphasis>
- is an invocation of a generic type with concrete values supplied for
- all of its type parameters (for example, <literal>List<String></literal> or <literal>List<Food></literal>).
- </para>
-
- <para>A generic type may be declared with multiple type parameters. In addition to simple type parameter names, type
- parameter declarations can also constrain the set of types allowed by using the <literal>extends</literal>
- keyword. Some examples follow:</para>
-
- <variablelist>
-
- <varlistentry>
- <term>class Foo<T> {...}</term>
- <listitem>
- <para>A class <literal>Foo</literal> with one type parameter, <literal>T</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Foo<T,S> {...}</term>
- <listitem>
- <para>A class <literal>Foo</literal> with two type parameters, <literal>T</literal> and <literal>S</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Foo<T extends Number> {...}</term>
- <listitem>
- <para>A class <literal>Foo</literal> with one type parameter <literal>T</literal>, where <literal>T</literal> must be
- instantiated as the type <literal>Number</literal> or a subtype of <literal>Number</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Foo<T, S extends T> {...}</term>
- <listitem>
- <para>A class <literal>Foo</literal> with two type parameters, <literal>T</literal> and <literal>S</literal>. <literal>Foo</literal>
- must be instantiated with a type <literal>S</literal> that is a subtype of the type specified for parameter <literal>T</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Foo<T extends Number & Comparable> {...}</term>
- <listitem>
- <para>A class <literal>Foo</literal> with one type parameter, <literal>T</literal>. <literal>Foo</literal>
- must be instantiated with a type that is a subtype of <literal>Number</literal> and that implements <literal>Comparable</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- </sect2>
-
- <sect2 id="using-generic-and-parameterized-types" xreflabel="using-generic-and-parameterized-types">
- <title>Using Generic and Parameterized Types</title>
-
- <para>You declare a variable (or a method/constructor argument) of a parameterized type by specifying a concrete type specfication for each type parameter in
- the generic type. The following example declares a list of strings and a list of numbers:</para>
-
- <programlisting><![CDATA[
- List<String> strings;
- List<Number> numbers;
- ]]></programlisting>
-
- <para>It is also possible to declare a variable of a generic type without specifying any values for the type
- parameters (a <emphasis>raw</emphasis> type). For example, <literal>List strings</literal>.
- In this case, unchecked warnings may be issued by the compiler
- when the referenced object is passed as a parameter to a method expecting a parameterized type such as a
- <literal>List<String></literal>. New code written in the Java 5 language would not be expected to use
- raw types.</para>
-
- <para>Parameterized types are instantiated by specifying type parameter values in the constructor call expression as in
- the following examples:</para>
-
- <programlisting><![CDATA[
- List<String> strings = new MyListImpl<String>();
- List<Number> numbers = new MyListImpl<Number>();
- ]]></programlisting>
-
- <para>
- When declaring parameterized types, the <literal>?</literal> wildcard may be used, which stands for "some type".
- The <literal>extends</literal> and <literal>super</literal> keywords may be used in conjunction with the wildcard
- to provide upper and lower bounds on the types that may satisfy the type constraints. For example:
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term>List<?></term>
- <listitem>
- <para>A list containing elements of some type, the type of the elements in the list is unknown.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>List<? extends Number></term>
- <listitem>
- <para>A list containing elements of some type that extends Number, the exact type of the elements in the list is unknown.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>List<? super Double></term>
- <listitem>
- <para>A list containing elements of some type that is a super-type of Double, the exact type of the elements in the list is unknown.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>
- A generic type may be extended as any other type. Given a generic type <literal>Foo<T></literal> then
- a subtype <literal>Goo</literal> may be declared in one of the following ways:
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term>class Goo extends Foo</term>
- <listitem>
- <para>Here <literal>Foo</literal> is used as a raw type, and the appropriate warning messages will be
- issued by the compiler on attempting to invoke methods in <literal>Foo</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Goo<E> extends Foo</term>
- <listitem>
- <para><literal>Goo</literal> is a generic type, but the super-type <literal>Foo</literal> is used as a raw
- type and the appropriate warning messages will be
- issued by the compiler on attempting to invoke methods defined by <literal>Foo</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Goo<E> extends Foo<E></term>
- <listitem>
- <para>This is the most usual form. <literal>Goo</literal> is a generic type with one parameter that extends
- the generic type <literal>Foo</literal> with that same parameter. So <literal>Goo<String<</literal> is
- a subclass of <literal>Foo<String></literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Goo<E,F> extends Foo<E></term>
- <listitem>
- <para><literal>Goo</literal> is a generic type with two parameters that extends
- the generic type <literal>Foo</literal> with the first type parameter of <literal>Goo</literal> being used
- to parameterize <literal>Foo</literal>. So <literal>Goo<String,Integer<</literal> is
- a subclass of <literal>Foo<String></literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>class Goo extends Foo<String></term>
- <listitem>
- <para><literal>Goo</literal> is a type that extends
- the parameterized type <literal>Foo<String></literal>.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>A generic type may implement one or more generic interfaces, following the type binding
- rules given above. A type may also implement one or more parameterized interfaces (for example,
- <literal>class X implements List<String></literal>, however a type may not at the same time
- be a subtype of two interface types which are different parameterizations of the same interface.</para>
- </sect2>
-
- <sect2 id="subtypes-supertypes-and-assignability" xreflabel="subtypes-supertypes-and-assignability">
- <title>Subtypes, Supertypes, and Assignability</title>
-
- <para>
- The supertype of a generic type <literal>C</literal> is the type given in the extends clause of
- <literal>C</literal>, or <literal>Object</literal> if no extends clause is present. Given the type declaration
- </para>
-
- <programlisting><![CDATA[
- public interface List<E> extends Collection<E> {... }
- ]]></programlisting>
-
- <para>
- then the supertype of <literal>List<E></literal> is <literal>Collection<E></literal>.
- </para>
-
- <para>
- The supertype of a parameterized type <literal>P</literal> is the type given in the extends clause of
- <literal>P</literal>, or <literal>Object</literal> if no extends clause is present. Any type parameters in
- the supertype are substituted in accordance with the parameterization of <literal>P</literal>. An example
- will make this much clearer: Given the type <literal>List<Double></literal> and the definition of
- the <literal>List</literal> given above, the direct supertype is
- <literal>Collection<Double></literal>. <literal>List<Double></literal> is <emphasis>not</emphasis>
- considered to be a subtype of <literal>List<Number></literal>.
- </para>
-
- <para>
- An instance of a parameterized type <literal>P<T1,T2,...Tn></literal>may be assigned to a variable of
- the same type or a supertype
- without casting. In addition it may be assigned to a variable <literal>R<S1,S2,...Sm></literal> where
- <literal>R</literal> is a supertype of <literal>P</literal> (the supertype relationship is reflexive),
- <literal>m <= n</literal>, and for all type parameters <literal>S1..m</literal>, <literal>Tm</literal> equals
- <literal>Sm</literal> <emphasis>or</emphasis> <literal>Sm</literal> is a wildcard type specification and
- <literal>Tm</literal> falls within the bounds of the wildcard. For example, <literal>List<String></literal>
- can be assigned to a variable of type <literal>Collection<?></literal>, and <literal>List<Double></literal>
- can be assigned to a variable of type <literal>List<? extends Number></literal>.
- </para>
-
- </sect2>
-
- <sect2 id="generic-methods-and-constructors" xreflabel="generic-methods-and-constructors">
- <title>Generic Methods and Constructors</title>
- <para>
- A static method may be declared with one or more type parameters as in the following declaration:
- </para>
-
- <programlisting><![CDATA[
- static <T> T first(List<T> ts) { ... }
- ]]></programlisting>
-
- <para>
- Such a definition can appear in any type, the type parameter <literal>T</literal> does not need to
- be declared as a type parameter of the enclosing type.
- </para>
-
- <para>
- Non-static methods may also be declared with one or more type parameters in a similar fashion:
- </para>
-
- <programlisting><![CDATA[
- <T extends Number> T max(T t1, T t2) { ... }
- ]]></programlisting>
-
- <para>The same technique can be used to declare a generic constructor.</para>
-
- </sect2>
-
- <sect2 id="erasure" xreflabel="erasure">
- <title>Erasure</title>
- <para>Generics in Java are implemented using a technique called <emphasis>erasure</emphasis>. All
- type parameter information is erased from the run-time type system. Asking an object of a parameterized
- type for its class will return the class object for the raw type (eg. <literal>List</literal> for an object
- declared to be of type <literal>List<String></literal>. A consequence of this is that you cannot at
- runtime ask if an object is an <literal>instanceof</literal> a parameterized type.</para>
- </sect2>
- </sect1>
-
- <!-- ===================================================================== -->
-
- <sect1 id="generics-inAspectJ5">
- <title>Generics in AspectJ 5</title>
-
- <para>
- 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 <emphasis>abstract</emphasis> aspects.
- </para>
-
- <sect2 id="matching-generic-and-parameterized-types-in-pointcut-expressions" xreflabel="matching-generic-and-parameterized-types-in-pointcut-expressions">
- <title>Matching generic and parameterized types in pointcut expressions</title>
-
- <para>
- 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 <literal>List</literal> will match
- the generic type <literal>List<E></literal> and any parameterization of that type
- (<literal>List<String>, List<?>, List<? extends Number></literal> 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.
- </para>
-
- <para>Generic methods and constructors, and members defined in generic types, may use type variables
- as part of their signature. For example:</para>
-
- <programlisting><![CDATA[
- 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() {...}
-
- }
- ]]></programlisting>
-
- <para>
- 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 <emphasis>erasure</emphasis>. Java 5 defines the
- rules for determing the erasure of a type as follows.
- </para>
-
- <para>Let <literal>|T|</literal> represent the erasure of some type <literal>T</literal>. Then:</para>
-
- <simplelist>
- <member>The erasure of a parameterized type <literal>T<T1,...,Tn></literal> is <literal>|T|</literal>.
- For example, the erasure of <literal>List<String></literal> is <literal>List</literal>.</member>
-
- <member>The erasure of a nested type <literal>T.C</literal> is <literal>|T|.C</literal>. For example,
- the erasure of the nested type <literal>Foo<T>.Bar</literal> is <literal>Foo.Bar</literal>.</member>
-
- <member>The erasure of an array type <literal>T[]</literal> is <literal>|T|[]</literal>. For example,
- the erasure of <literal>List<String>[]</literal> is <literal>List[]</literal>.</member>
-
- <member>The erasure of a type variable is its leftmost bound. For example, the erasure of a
- type variable <literal>P</literal> is <literal>Object</literal>, and the erasure of a type
- variable <literal>N extends Number</literal> is <literal>Number</literal>.</member>
-
- <member>The erasure of every other type is the type itself</member>
- </simplelist>
-
- <!-- see tests/java5/generics/ajdk/ErasureMatching.aj -->
- <para>Applying these rules to the earlier examples, we find that the methods defined in <literal>Utils</literal>
- can be matched by a signature pattern matching <literal>static Object Utils.first(List)</literal> and
- <literal>Number Utils.max(Number, Number)</literal> respectively. The members of the generic type
- <literal>G</literal> can be matched by a signature pattern matching <literal>Object G.myData</literal> and
- <literal>public List G.getAllDataItems()</literal> respectively.</para>
-
- <sect3>
- <title>Restricting matching using parameterized types</title>
-
- <para>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 <literal>Foo</literal>:</para>
-
- <programlisting><![CDATA[
- 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);
- }
-
- }
- ]]></programlisting>
-
- <!-- see tests/java5/generics/ajdk/SimpleParameterizedTypeExamples.aj -->
-
- <para>Then a <literal>get</literal> join point for the field <literal>myStrings</literal> can be matched by the
- pointcut <literal>get(List Foo.myStrings)</literal> and by the pointcut <literal>get(List<String> Foo.myStrings)</literal>,
- but <emphasis>not</emphasis> by the pointcut <literal>get(List<Number> *)</literal>.</para>
-
- <para>A <literal>get</literal> join point for the field <literal>myFloats</literal> can be matched by the
- pointcut <literal>get(List Foo.myFloats)</literal>, the pointcut <literal>get(List<Float> *)</literal>,
- and the pointcut <literal>get(List<Number+> *)</literal>. This last example shows how AspectJ type
- patterns can be used to match type parameters types just like any other type. The pointcut
- <literal>get(List<Double> *)</literal> does <emphasis>not</emphasis> match.</para>
-
- <para>The execution of the methods <literal>getStrings</literal> and <literal>getFloats</literal> can be
- matched by the pointcut expression <literal>execution(List get*(..))</literal>, and the pointcut
- expression <literal>execution(List<*> get*(..))</literal>, but only <literal>getStrings</literal>
- is matched by <literal>execution(List<String> get*(..))</literal> and only <literal>getFloats</literal>
- is matched by <literal>execution(List<Number+> get*(..))</literal></para>
-
- <para>A call to the method <literal>addStrings</literal> can be matched by the pointcut expression
- <literal>call(* addStrings(List))</literal> and by the expression <literal>call(* addStrings(List<String>))</literal>,
- but <emphasis>not</emphasis> by the expression <literal>call(* addStrings(List<Number>))</literal>.
- </para>
-
- <para>Remember that any type variable reference in a generic member is
- <emphasis>always</emphasis> matched by its erasure. Thus given the following
- example:</para>
-
- <programlisting><![CDATA[
- class G<T> {
-
- List<T> foo(List<String> ls) { return null; }
-
- }
- ]]></programlisting>
-
- <!-- see tests/java5/generics/ajdk/MixedParameterizedAndTypeVariables.aj -->
- <para>The execution of <literal>foo</literal> can be matched by
- <literal>execution(List foo(List))</literal>,
- <literal>execution(List foo(List<String>>))</literal>, and
- <literal>execution(* foo(List<String<))</literal>but
- <emphasis>not</emphasis> by <literal>execution(List<Object> foo(List<String>>)</literal>
- since the erasure of <literal>List<T></literal> is <literal>List</literal>
- and not <literal>List<Object></literal>.
- </para>
-
- </sect3>
-
- <sect3>
- <title>Generic wildcards and signature matching</title>
-
- <para>
- When it comes to signature matching, a type parameterized using a generic wildcard is a distinct type.
- For example, <literal>List<?></literal> is a very different type to <literal>List<String></literal>,
- even though a variable of type <literal>List<String></literal> can be assigned to a variable of
- type <literal>List<?></literal>. Given the methods:
- </para>
-
- <programlisting><![CDATA[
- class C {
-
- public void foo(List<? extends Number> listOfSomeNumberType) {}
-
- public void bar(List<?> listOfSomeType) {}
-
- public void goo(List<Double> listOfDoubles) {}
-
- }
- ]]></programlisting>
-
- <!-- see java5/generics/ajdk/SignatureWildcards.aj -->
-
- <variablelist>
-
- <varlistentry>
- <term>execution(* C.*(List))</term>
- <listitem>
- <para>Matches an execution join point for any of the three methods.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>execution(* C.*(List<? extends Number>))</term>
- <listitem>
- <para>matches only the
- execution of <literal>foo</literal>, and <emphasis>not</emphasis> the execution
- of <literal>goo</literal> since <literal>List<? extends Number></literal> and
- <literal>List<Double></literal> are distinct types.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>execution(* C.*(List<?>))</term>
- <listitem>
- <para>matches only the execution of <literal>bar</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>execution(* C.*(List<? extends Object+>))</term>
- <listitem>
- <para>matches both the execution of <literal>foo</literal> and the execution of <literal>bar</literal>
- since the upper bound of <literal>List<?></literal> is implicitly <literal>Object</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- </sect3>
-
- <sect3>
- <title>Treatment of bridge methods</title>
-
- <para>Under certain circumstances a Java 5 compiler is required to create <emphasis>bridge
- methods</emphasis> that support the compilation of programs using raw types. Consider the types</para>
-
- <programlisting><![CDATA[
- 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;
- }
-
- }
- ]]></programlisting>
-
- <para>The class <literal>SubGeneric</literal> extends <literal>Generic</literal>
- and overrides the method <literal>foo</literal>. Since the upper bound of the type variable
- <literal>N</literal> in <literal>SubGeneric</literal> is different to the upper bound of
- the type variable <literal>T</literal> in <literal>Generic</literal>, the method <literal>foo</literal>
- in <literal>SubGeneric</literal> has a different erasure to the method <literal>foo</literal>
- in <literal>Generic</literal>. This is an example of a case where a Java 5 compiler will create
- a <emphasis>bridge method</emphasis> in <literal>SubGeneric</literal>. Although you never see it,
- the bridge method will look something like this:</para>
-
- <programlisting><![CDATA[
- public Object foo(Object arg) {
- Number n = (Number) arg; // "bridge" to the signature defined in this type
- return foo(n);
- }
- ]]></programlisting>
-
- <!-- see java5/generics/ajdk/BridgeMethodExamples.aj -->
- <para>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 <literal>execution(Object SubGeneric.foo(Object))</literal>
- does not match anything. (The pointcut <literal>execution(Object Generic.foo(Object))</literal> matches the
- execution of <literal>foo</literal> in both <literal>Generic</literal> and <literal>SubGeneric</literal> since
- both are implementations of <literal>Generic.foo</literal>).
- </para>
-
- <para>It <emphasis>is</emphasis> possible to <emphasis>call</emphasis> a bridge method as the following short
- code snippet demonstrates. Such a call <emphasis>does</emphasis> result in a call join point for the call to
- the method.
- </para>
-
- <programlisting><![CDATA[
- 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
- ]]></programlisting>
-
- </sect3>
-
- <sect3>
- <title>Runtime type matching with this(), target() and args()</title>
-
- <para>The <literal>this()</literal>, <literal>target()</literal>, and
- <literal>args()</literal> 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 <literal>this()</literal> and
- <literal>target()</literal> pointcuts. Parameterized types may however be used in conjunction with
- <literal>args()</literal>. Consider the following class
- </para>
-
- <programlisting><![CDATA[
- public class C {
-
- public void foo(List<String> listOfStrings) {}
-
- public void bar(List<Double> listOfDoubles) {}
-
- public void goo(List<? extends Number> listOfSomeNumberType) {}
-
- }
- ]]></programlisting>
-
- <!-- see java5/generics/ajdk/ArgsExamples.aj -->
-
- <variablelist>
-
- <varlistentry>
- <term>args(List)</term>
- <listitem>
- <para>will match an execution or call join point for any of
- these methods
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>args(List<String>)</term>
- <listitem>
- <para>will match an execution
- or call join point for <literal>foo</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>args(List<Double>)</term>
- <listitem>
- <para>matches an execution or call join point for <literal>bar</literal>, and <emphasis>may</emphasis> match
- at an execution or call join point for <literal>goo</literal> since it is legitimate to pass an
- object of type <literal>List<Double></literal> to a method expecting a <literal>List<? extends Number></literal>.
- </para>
- <para>
- 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 <emphasis>unchecked</emphasis> warning.
- For example, compiling the aspect <literal>A</literal> below with the class <literal>C</literal> 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]";
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <programlisting><![CDATA[
- public aspect A {
-
- before(List<Double> listOfDoubles) : execution(* C.*(..)) && args(listOfDoubles) {
- for (Double d : listOfDoubles) {
- // do something
- }
- }
-
- }
- ]]></programlisting>
-
- <para>Like all Lint messages, the <literal>uncheckedArgument</literal> 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 <literal>@SuppressAjWarnings</literal> which is
- the AspectJ equivalent of Java's <literal>@SuppressWarnings</literal> annotation. If the
- advice is annotated with <literal>@SuppressWarnings</literal> then <emphasis>all</emphasis>
- lint warnings issued during matching of pointcut associated with the advice will be
- suppressed. To suppress just an <literal>uncheckedArgument</literal> warning, use the
- annotation <literal>@SuppressWarnings("uncheckedArgument")</literal> as in the following
- examples:
- </para>
-
- <programlisting><![CDATA[
- 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
- }
- }
-
- }
- ]]></programlisting>
-
- <para>
- The safest way to deal with <literal>uncheckedArgument</literal> 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
- <literal>args</literal> with a <literal>call</literal> or <literal>execution</literal> signature matching
- pointcut. In the following example the advice will match the execution of <literal>bar</literal> but not
- of <literal>goo</literal> since the signature of <literal>goo</literal> is not matched by the execution pointcut
- expression.
- </para>
-
- <programlisting><![CDATA[
- public aspect A {
-
- before(List<Double> listOfDoubles) : execution(* C.*(List<Double>)) && args(listOfDoubles) {
- for (Double d : listOfDoubles) {
- // do something
- }
- }
-
- }
- ]]></programlisting>
-
- <para>Generic wildcards can be used in args type patterns, and matching follows regular Java 5 assignability rules. For
- example, <literal>args(List<?>)</literal> will match a list argument of any type, and
- <literal>args(List<? extends Number>)</literal> will match an argument of type
- <literal>List<Number>, List<Double>, List<Float></literal> and so on. Where a match cannot be
- fully statically determined, the compiler will once more issue an <literal>uncheckedArgument</literal> warning.
- </para>
-
- <para>Consider the following program:</para>
-
- <programlisting><![CDATA[
- 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...
- }
- }
- ]]></programlisting>
-
- <!-- see java5/generics/ajdk/WildcardArgsExamples.aj -->
-
- <para>From the signature of <literal>foo</literal> all we know is that the runtime argument will be an instance of
- <literal>Object</literal>.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 <literal>c.foo("hi")</literal> since <literal>String</literal>
- is not an instance of <literal>List</literal>. The advice <emphasis>will</emphasis> execute at the call join points
- for <literal>c.foo(ls)</literal> and <literal>c.foo(ld)</literal> since in both cases the argument is an instance of
- <literal>List</literal>.
- </para>
-
- <para>Combine a wildcard argument type with a signature pattern to avoid unchecked argument matches. In the example
- below we use the signature pattern <literal>List<Number+></literal> to match a call to any method taking
- a <literal>List<Number>, List<Double>, List<Float></literal> and so on. In addition the
- signature pattern <literal>List<? extends Number+></literal> can be used to match a call to a method
- declared to take a <literal>List<? extends Number></literal>, <literal>List<? extends Double></literal>
- and so on. Taken together, these restrict matching to only
- those join points at which the argument is guaranteed to be an instance of <literal>List<? extends Number></literal>.</para>
-
-
- <programlisting><![CDATA[
- aspect A {
- before(List<? extends Number> aListOfSomeNumberType)
- : (call(* foo(List<Number+>)) || call(* foo(List<? extends Number+>)))
- && args(aListOfSomeNumberType) {
- // process list...
- }
- }
- ]]></programlisting>
-
- </sect3>
-
- <sect3>
- <title>Binding return values in after returning advice</title>
-
- <para>
- 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 <literal>List</literal>, and makes
- the returned list available to the body of the advice.
- </para>
-
- <programlisting><![CDATA[
- public aspect A {
-
- pointcut executionOfAnyMethodReturningAList() : execution(List *(..));
-
- after() returning(List<?> listOfSomeType) : executionOfAnyMethodReturningAList() {
- for (Object element : listOfSomeType) {
- // process element...
- }
- }
-
- }
- ]]></programlisting>
-
- <!-- see java5/generics/ajdk/AfterReturningExamples.aj -->
- <para>The pointcut uses the raw type pattern <literal>List</literal>, and hence it
- matches methods returning any kind of list (<literal>List<String>, List<Double></literal>,
- and so on). We've chosen to bind the returned list as the parameterized type
- <literal>List<?></literal> in the advice since Java's type checking will now ensure
- that we only perform safe operations on the list.</para>
-
- <para>Given the class</para>
-
- <programlisting><![CDATA[
- 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) {...}
-
- }
- ]]></programlisting>
-
- <para>The advice in the aspect below will run after the execution of <literal>bar</literal>
- and bind the return value. It will also run after the execution of <literal>goo</literal> and
- bind the return value, but gives an <literal>uncheckedArgument</literal> warning during
- compilation. It does <emphasis>not</emphasis> run after the execution of <literal>foo</literal>.
- </para>
-
- <programlisting><![CDATA[
- public aspect Returning {
-
- after() returning(List<Double> listOfDoubles) : execution(* C.*(..)) {
- for(Double d : listOfDoubles) {
- // process double...
- }
- }
-
- }
- ]]></programlisting>
-
- <para>As with <literal>args</literal> you can guarantee that after returning advice only
- executes on lists <emphasis>statically determinable</emphasis> to be of the right
- type by specifying a return type pattern in the associated pointcut. The
- <literal>@SuppressAjWarnings</literal> annotation can also be used if desired.</para>
-
- </sect3>
-
- <sect3>
- <title>Declaring pointcuts inside generic types</title>
-
- <para>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.</para>
-
- <para>Consider the generic type <literal>Generic</literal> with a pointcut <literal>foo</literal>:
- </para>
-
- <programlisting><![CDATA[
- public class Generic<T> {
-
- /**
- * matches the execution of any implementation of a method defined for T
- */
- public pointcut foo() : execution(* T.*(..));
-
- }
- ]]></programlisting>
-
- <!-- see java5/generics/ajdk/PointcutInGenericClassExample.aj -->
-
- <para>Such a pointcut must be refered to using a parameterized reference as shown
- below.</para>
-
- <programlisting><![CDATA[
- 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() { }
-
- }
- ]]></programlisting>
-
- </sect3>
-
- </sect2>
-
- <sect2 id="inter-type-declarations" xreflabel="inter-type-declarations">
- <title>Inter-type Declarations</title>
-
- <para>
- 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:
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term><T extends Number> T Utils.max(T first, T second) {...}</term>
- <listitem>
- <para>Declares a generic instance method <literal>max</literal> on the class <literal>Util</literal>.
- The <literal>max</literal> method takes two arguments, <literal>first</literal> and <literal>second</literal> 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.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>static <E> E Utils.first(List<E> elements) {...}</term>
- <listitem>
- <para>Declares a static generic method <literal>first</literal> on the class <literal>Util</literal>.
- The <literal>first</literal> method takes a list of elements of some type, and returns an instance
- of that type.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term><T> Sorter.new(List<T> elements,Comparator<? super T> comparator) {...}</term>
- <listitem>
- <para>Declares a constructor on the class <literal>Sorter</literal>.
- The constructor takes a list of elements of some type, and a comparator that can compare instances
- of the element type.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>
- 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 <emphasis>names</emphasis> do not have to match.
- For example, given the generic type <literal>Foo<T,S extends Number></literal> then:
- </para>
-
- <variablelist>
-
- <varlistentry>
- <term>String Foo.getName() {...}</term>
- <listitem>
- <para>Declares a <literal>getName</literal> method on behalf of the type <literal>Foo</literal>. It is
- not possible to refer to the type parameters of Foo in such a declaration.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>public R Foo<Q, R>.getMagnitude() {...}</term>
- <listitem>
- <para>Declares a method <literal>getMagnitude</literal> on the generic class <literal>Foo</literal>.
- The method returns an instance of the type substituted for the second type parameter in an invocation
- of <literal>Foo</literal> If <literal>Foo</literal> is declared as
- <literal>Foo<T,N extends Number> {...}</literal> then this inter-type declaration is
- equivalent to the declaration of a method <literal>public N getMagnitude()</literal>
- within the body of <literal>Foo</literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>R Foo<Q, R extends Number>.getMagnitude() {...}</term>
- <listitem>
- <para>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).
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>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) <literal>Bar<String></literal>, you can only declare members on the generic
- type <literal>Bar<T></literal>.
- </para>
-
- </sect2>
-
- <sect2 id="declare-parents" xreflabel="declare-parents">
- <title>Declare Parents</title>
-
- <para>Both generic and parameterized types can be used as the parent type in a <literal>declare parents</literal>
- 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 <literal>declare parents</literal> statement.</para>
-
- <variablelist>
-
- <varlistentry>
- <term>declare parents: Foo implements List<String></term>
- <listitem>
- <para>The <literal>Foo</literal> type implements the <literal>List<String></literal> interface. If
- <literal>Foo</literal> already implements some other parameterization of the <literal>List</literal>
- interface (for example, <literal>List<Integer></literal> then a compilation error will result since a
- type cannot implement multiple parameterizations of the same generic interface type.
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- </sect2>
-
- <sect2 id="declare-soft" xreflabel="declare-soft">
- <title>Declare Soft</title>
- <para>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 <literal>Throwable</literal> (JLS 8.1.2).</para>
- </sect2>
-
- <sect2 id="generic-aspects" xreflabel="generic-aspects">
- <title>Generic Aspects</title>
-
- <para>
- AspectJ 5 allows an <emphasis>abstract</emphasis> 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.
- </para>
-
- <para>Given the aspect declaration:</para>
-
- <programlisting><![CDATA[
- public abstract aspect ParentChildRelationship<P,C> {
- ...
- }
- ]]></programlisting>
-
- <para>then</para>
-
- <variablelist>
-
- <varlistentry>
- <term>public aspect FilesInFolders extends ParentChildRelationship<Folder,File> {...</term>
- <listitem>
- <para>declares a concrete sub-aspect, <literal>FilesInFolders</literal> which extends the
- parameterized abstract aspect <literal>ParentChildRelationship<Folder,File></literal>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>public aspect FilesInFolders extends ParentChildRelationship {...</term>
- <listitem>
- <para>results in a compilation error since the <literal>ParentChildRelationship</literal> aspect must
- be fully parameterized.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>public aspect ThingsInFolders<T> extends ParentChildRelationship<Folder,T></term>
- <listitem>
- <para>results in a compilation error since concrete aspects may not have type parameters.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>public abstract aspect ThingsInFolders<T> extends ParentChildRelationship<Folder,T></term>
- <listitem>
- <para>declares a sub-aspect of <literal>ParentChildRelationship</literal> in which <literal>Folder</literal>
- plays the role of parent (is bound to the type variable <literal>P</literal>).
- </para>
- </listitem>
- </varlistentry>
-
- </variablelist>
-
- <para>The type parameter variables from a generic aspect declaration may be used in place of a type within any
- member of the aspect, <emphasis>except for within inter-type declarations</emphasis>.
- For example, we can declare a <literal>ParentChildRelationship</literal> aspect to
- manage the bi-directional relationship between parent and child nodes as follows:
- </para>
-
- <programlisting><![CDATA[
- /**
- * 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);
-
- }
-
- ]]></programlisting>
-
-
- <para>
- 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:
- </para>
-
- <programlisting><![CDATA[
- public aspect ASTNodeContainment extends ParentChildRelationship<ASTNode,ASTNode> {
-
- before(ASTNode parent, ASTNode child) : addingChild(parent, child) {
- ...
- }
-
- }
- ]]></programlisting>
-
- <para>
- As a result of this declaration, <literal>ASTNode</literal> gains members:
- </para>
-
- <simplelist>
- <member><literal>List<ASTNode> children</literal></member>
- <member><literal>ASTNode parent</literal></member>
- <member><literal>List<ASTNode>getChildren()</literal></member>
- <member><literal>ASTNode getParent()</literal></member>
- <member><literal>void addChild(ASTNode child)</literal></member>
- <member><literal>void removeChild(ASTNode child)</literal></member>
- <member><literal>void setParent(ASTNode parent)</literal></member>
- </simplelist>
-
- <para>
- In a system managing orders, we could declare the concrete aspect:
- </para>
-
- <programlisting><![CDATA[
- public aspect OrderItemsInOrders extends ParentChildRelationship<Order,OrderItem> {
-
- }
- ]]></programlisting>
-
- <para>
- As a result of this declaration, <literal>Order</literal> gains members:
- </para>
-
- <simplelist>
- <member><literal>List<OrderItem> children</literal></member>
- <member><literal>List<OrderItem> getChildren()</literal></member>
- <member><literal>void addChild(OrderItem child)</literal></member>
- <member><literal>void removeChild(OrderItem child)</literal></member>
- </simplelist>
-
- <para>and <literal>OrderItem</literal> gains members:</para>
-
- <simplelist>
- <member><literal>Order parent</literal></member>
- <member><literal>Order getParent()</literal></member>
- <member><literal>void setParent(Order parent)</literal></member>
- </simplelist>
-
-
- <para>A second example of an abstract aspect, this time for handling exceptions in a uniform
- manner, is shown below:</para>
-
- <programlisting><![CDATA[
- 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);
- }
-
- }
- ]]></programlisting>
-
- <para>Notice how the type variable <literal>T extends Throwable</literal> 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 <literal>IOExceptions</literal>.</para>
-
- <programlisting><![CDATA[
- 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);
- }
- }
- ]]></programlisting>
-
- </sect2>
-
- </sect1>
-
- </chapter>
-
|