diff options
author | acolyer <acolyer> | 2005-06-19 14:15:39 +0000 |
---|---|---|
committer | acolyer <acolyer> | 2005-06-19 14:15:39 +0000 |
commit | ca6ec31223df4c73df0103a67cb7ce99be75a1aa (patch) | |
tree | dcb048062d5ae21e331f5fb9b3ab431aede346b9 /docs/adk15ProgGuideDB/generics.xml | |
parent | f7b040b3b6e82a3cd61a7e991b87ad33208f5420 (diff) | |
download | aspectj-ca6ec31223df4c73df0103a67cb7ce99be75a1aa.tar.gz aspectj-ca6ec31223df4c73df0103a67cb7ce99be75a1aa.zip |
first complete version of the generics chapter.
Diffstat (limited to 'docs/adk15ProgGuideDB/generics.xml')
-rw-r--r-- | docs/adk15ProgGuideDB/generics.xml | 273 |
1 files changed, 254 insertions, 19 deletions
diff --git a/docs/adk15ProgGuideDB/generics.xml b/docs/adk15ProgGuideDB/generics.xml index ff74040e1..7e04bf01c 100644 --- a/docs/adk15ProgGuideDB/generics.xml +++ b/docs/adk15ProgGuideDB/generics.xml @@ -1,4 +1,5 @@ -<!--<!DOCTYPE chapter SYSTEM "file:/C:/Documents%20and%20Settings/colyer/My%20Documents/projects/aspectjdev/lib/docbook/docbook-dtd/docbookx.dtd"> --> +<!--<!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> @@ -580,7 +581,8 @@ <para>A type variable declaration list can appear following any pointcut designator except for <literal>handler</literal> (Java 5 does not permit a generic class to be a direct or indirect subtype of <literal>Throwable</literal> - - see JLS 8.1.2), <literal>if, cflow, cflowbelow</literal>, and the annotation pointcut designators + - see JLS 8.1.2), the dynamic pointcuts <literal>this, target, args, if, cflow, cflowbelow</literal>, + and the annotation pointcut designators (<literal>@args, @this, @within</literal> and so on).</para> </sect3> @@ -892,7 +894,6 @@ <sect3> <title>Call, get and set pointcuts</title> - </sect3> <para> The <literal>call, get,</literal> and <literal>set</literal> join points can occur on the client @@ -953,32 +954,233 @@ </para> Some examples follow: + + <variablelist> + + <varlistentry> + <term>call(* List<?>.*(..))</term> + <listitem> + <para>matches a call to any method of a <literal>List<?></literal> (a call where the + target is declared to be a <literal>List<?></literal>). For example: + </para> + <programlisting><![CDATA[ + int countItems(List<?> anyList) { + return anyList.size(); // matched by call(* List<?>.*(..)) + } + ]]></programlisting> + + </listitem> + </varlistentry> + + <varlistentry> + <term>call<T>(* List<T>.*(..))</term> + <listitem> + <para>matches any call to an operation defined in the generic type + <literal>List<E></literal>. This includes calls made to <literal>List<String></literal>, + <literal>List<Number></literal>, <literal>List<? super Foo></literal> and so on. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>get<T>(T *<T extends Account>.*)</term> + <listitem> + <para>matches the get of any field defined in a generic type with one type parameter that has + an upper bound of <literal>Account</literal>. The field has the type of the type parameter, and + can be of any name. This pointcut expression matches both gets of the field within the + declaring type, and also gets on parameterized instances of the type. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>set(Account Foo<Account>.*Account)</term> + <listitem> + <para>matches the set of a field of type <literal>Account</literal> where the target + is of type <literal>Foo<Account></literal> and the field name ends with "Account". Does not + match sets of any "*Account" field occurring within the <literal>Foo</literal> type itself. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>call(* List<? extends Number>.add(..))</term> + <listitem> + <para>matches any call to add an element to a list of type <literal>List<? extends Number></literal>. + Does not match calls to add elements to lists of type <literal>List<Number></literal> or + <literal>List<Double></literal> as these are distinct types. + </para> + </listitem> + </varlistentry> + + <varlistentry> + <term>call(* List<Number+>.add(..))</term> + <listitem> + <para>matches any call to add an element to a list of type <literal> Number</literal> or + any subclass of <literal>Number</literal>. For example, <literal>List<Number>, + List<Double> List<Float></literal>. + Does not match calls to add elements to lists of type <literal>List<? extends Number></literal> + as this is a distinct type. + </para> + </listitem> + </varlistentry> + + </variablelist> + </sect3> - - <sect3> <title>Handler</title> + + <para> + The Java Language Specification states that a generic class may not be a direct or indirect + subclass of <literal>Throwable</literal>. Therefore it is a compilation error to use a generic + or parameterized type pattern in a <literal>handler</literal> pointcut expression. + </para> + </sect3> <sect3> <title>Runtime type matching: this, target and args</title> - </sect3> + <para> + Java 5 generics are implemented using a technique known an <emphasis>erasure</emphasis>. + In particular, what gets "erased" is the ability to find out the parameterized runtime type + of an instance of a generic type. You can ask if something is an <literal>instanceof List</literal>, + but not if something is an <literal>instanceof List<String></literal> + </para> + <para> + The <literal>this, target</literal> and <literal>args</literal> pointcut designators all match + based on the runtime type of the appropriate object (this, target, or argument) at a join point. + To match any parameterization of a generic type, simply use the raw type (type variables are + not permitted with these designators). For example: + </para> + + <variablelist> + <varlistentry> + <term>target(List)</term> + <listitem> + <para>matches any call to an instance of <literal>List</literal> (including + <literal>List<String>, List<Number></literal>, and so on. + </para> + </listitem> + </varlistentry> - <programlisting><![CDATA[ + <varlistentry> + <term>args (List)</term> + <listitem> + <para>matches any join point with a single argument that is an instance of + <literal>List</literal>. + </para> + </listitem> + </varlistentry> - call(* List<?>.*(..)) - call(* List<? extends Number>.*(..)) - call(* List<? super Double>.*(..)) - - this/target/args - examples with "+" + </variablelist> + + <para> + To match specific parameterizations of a generic type, simply use the type that you require + the relevant object to be an instance of inside the pointcut expression. For example: + <literal>target(List<String>)</literal>. + </para> + <para> + Recall that runtime tests to determine whether an object is an instance of a parameterized + type are not possible due to erasure. Therefore AspectJ matching behaviour with + parameterized types for <literal>this, target</literal> and <literal>args</literal> is as follows. + </para> + + <simplelist> + <member>If it can be statically determined that a given object will always be an instance + of the required type, then the pointcut expressions matches. For example, given a variable + <literal>bankAccounts</literal> + of type <literal>Set<BankAccount></literal> and the pointcut expression + <literal>target(Set<BankAccount>)</literal> then any call made to + <literal>bankAccounts</literal> will be matched.</member> + <member>If it can be statically determined that a given object can never be an + instance of the required type, then the pointcut expression does not match. The + expression <literal>target(List<String>)</literal>will never match a call made + using a variable of type <literal>List<Number></literal> (it is not possible for + a type to implement two different parameterizations of the same interface).</member> + <member>If an object <emphasis>might</emphasis> be an instance of the required + type in some circumstances but not in others, then since it is not possible to perform + the runtime test, AspectJ deems the pointcut expression to match, but issues an + unchecked warning. This is analogous to the behaviour of the Java compiler when + converting between raw and parameterized types. Given a variable of type + <literal>List<? extends Number></literal> and a call join point with + target pointcut expression <literal>target(List<Double>)</literal> then + the expression matches but with an unchecked warning. The warning can be suppressed + by annotating the associated advice with either <literal>@SuppressAjWarnings</literal> + or <literal>@SuppressAjWarnings("unchecked")</literal>.</member> + </simplelist> + + <para> + When using a parameterized type with the + <literal>this</literal> pointcut designator then a joinpoint is unambiguously + matched if and only if one or more of the following conditions hold: + </para> + + <simplelist> + <member>the runtime type of the <literal>this</literal> object extends or + implements the parameterized type. For example, + <literal>class Foo implements List<String></literal> will match + <literal>this(List<String>)</literal>.</member> + <member> + The parameterized "this" type is given using a generics wildcard in the pointcut + expression, and the bounds of + the generic runtime type of <literal>this</literal> are such that all valid parameterizations + are matched by the wildcard. For example, the pointcut expression + <literal>this(List<? extends Number>)</literal> will match a <literal>this</literal> + object of type <literal>class Foo<N extends Number> implements List<N></literal>, + but not an object of type <literal>class Foo<N> implements List<N></literal>. + </member> + </simplelist> + + <para> + You've already seen some examples of using the generic wildcard <literal>?</literal> + in parameterized type patterns. Since <literal>this, target</literal> and + <literal>args</literal> match using an instance of test, the generic wildcard can be useful in + specifying an acceptable range of parameterized types to match. When used in the binding + form, the same restrictions on operations permitted on the bound variable apply as when a + method declares a parameter with a wildcard type. For example, in the advice below, it is + a compilation error to attemp to add an element into the list <literal>aList</literal>. + </para> + + <programlisting><![CDATA[ + before(List<? extends Number> aList) : + execution(* org.xyz.Foo.*(..)) && args(aList) { + aList.add(new Double(5.0d)); // Compilation error on this line + } ]]></programlisting> + </sect3> + <sect3> <title>Declaring pointcuts in generic classes</title> + + <para> + AspectJ permits pointcuts to be declared in classes as well as aspects. A pointcut defined + inside a generic class may not use the type variables of the class in the pointcut expression + (just as static members of a generic class may not use type variables). + For example: + </para> + + <programlisting><![CDATA[ + public class Foo<T extends Number> { + + ... + + // Not allowed - uses T in the pointcut expression + public pointcut fooOperationCall(T t) : + call(* Foo<T>.*(T)) && args(t); + + + // permitted, but recommended to use an alternate variable name in the local + // type variable declaration - e.g. execution<S>(...) + public pointcut fooExecution(Number n) : + execution<T>(* Foo<T>.*(T)) && args(n); + } + ]]></programlisting> + </sect3> </sect2> @@ -1030,8 +1232,8 @@ <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 and - their bounds given in the inter-type declararation must be compatible with type parameter definitions in + 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> @@ -1048,7 +1250,7 @@ </varlistentry> <varlistentry> - <term>R Foo<Q, R extends Number>.getMagnitude() {...}</term> + <term>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 @@ -1058,10 +1260,11 @@ </varlistentry> <varlistentry> - <term>R Foo<Q, R>.getMagnitude() {...}</term> + <term>R Foo<Q, R extends Number>.getMagnitude() {...}</term> <listitem> - <para>Results in a compilation error since the generic type <literal>Foo</literal> with two unbounded - type parameters cannot be found. + <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> @@ -1244,6 +1447,20 @@ * Each child has a parent */ private P C.parent; + + /** + * Parents provide access to their children + */ + public List<C> P.getChildren() { + return Collections.unmodifiableList(children); + } + + /** + * A child provides access to its parent + */ + public P C.getParent() { + return parent; + } /** * ensure bi-directional navigation on adding a child @@ -1308,6 +1525,8 @@ <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> @@ -1329,6 +1548,7 @@ <simplelist> <member><literal>List<File> children</literal></member> + <member><literal>List<File> getChildren()</literal></member> <member><literal>void addChild(File child)</literal></member> <member><literal>void removeChild(File child)</literal></member> </simplelist> @@ -1337,6 +1557,7 @@ <simplelist> <member><literal>Folder parent</literal></member> + <member><literal>Folder getParent()</literal></member> <member><literal>void setParent(Folder parent)</literal></member> </simplelist> @@ -1360,6 +1581,20 @@ private Parent Child.parent; /** + * Parents provide access to their children + */ + public List<Children> Parent.getChildren() { + return Collections.unmodifiableList(children); + } + + /** + * A child provides access to its parent + */ + public Parent Children.getParent() { + return parent; + } + + /** * ensure bi-directional navigation on adding a child */ public void Parent.addChild(Child child) { |