1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270 |
- <!--<!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-java5" xreflabel="declare-parents-java5">
- <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>
-
|