From: acolyer Date: Sun, 19 Jun 2005 14:15:39 +0000 (+0000) Subject: first complete version of the generics chapter. X-Git-Tag: PRE_ANDY~136 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=ca6ec31223df4c73df0103a67cb7ce99be75a1aa;p=aspectj.git first complete version of the generics chapter. --- 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 @@ - + Generics @@ -580,7 +581,8 @@ A type variable declaration list can appear following any pointcut designator except for handler (Java 5 does not permit a generic class to be a direct or indirect subtype of Throwable - - see JLS 8.1.2), if, cflow, cflowbelow, and the annotation pointcut designators + - see JLS 8.1.2), the dynamic pointcuts this, target, args, if, cflow, cflowbelow, + and the annotation pointcut designators (@args, @this, @within and so on). @@ -892,7 +894,6 @@ Call, get and set pointcuts - The call, get, and set join points can occur on the client @@ -953,32 +954,233 @@ Some examples follow: + + + + + call(* List<?>.*(..)) + + matches a call to any method of a List<?> (a call where the + target is declared to be a List<?>). For example: + + anyList) { + return anyList.size(); // matched by call(* List.*(..)) + } + ]]> + + + + + + call<T>(* List<T>.*(..)) + + matches any call to an operation defined in the generic type + List<E>. This includes calls made to List<String>, + List<Number>, List<? super Foo> and so on. + + + + + + get<T>(T *<T extends Account>.*) + + matches the get of any field defined in a generic type with one type parameter that has + an upper bound of Account. 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. + + + + + + set(Account Foo<Account>.*Account) + + matches the set of a field of type Account where the target + is of type Foo<Account> and the field name ends with "Account". Does not + match sets of any "*Account" field occurring within the Foo type itself. + + + + + + call(* List<? extends Number>.add(..)) + + matches any call to add an element to a list of type List<? extends Number>. + Does not match calls to add elements to lists of type List<Number> or + List<Double> as these are distinct types. + + + + + + call(* List<Number+>.add(..)) + + matches any call to add an element to a list of type Number or + any subclass of Number. For example, List<Number>, + List<Double> List<Float>. + Does not match calls to add elements to lists of type List<? extends Number> + as this is a distinct type. + + + + + + - - Handler + + + The Java Language Specification states that a generic class may not be a direct or indirect + subclass of Throwable. Therefore it is a compilation error to use a generic + or parameterized type pattern in a handler pointcut expression. + + Runtime type matching: this, target and args - + + Java 5 generics are implemented using a technique known an erasure. + 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 instanceof List, + but not if something is an instanceof List<String> + + + The this, target and args 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: + + + + + target(List) + + matches any call to an instance of List (including + List<String>, List<Number>, and so on. + + + - + args (List) + + matches any join point with a single argument that is an instance of + List. + + + - call(* List.*(..)) - call(* List.*(..)) - call(* List.*(..)) - - this/target/args - examples with "+" + + + + 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: + target(List<String>). + + + 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 this, target and args is as follows. + + + + 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 + bankAccounts + of type Set<BankAccount> and the pointcut expression + target(Set<BankAccount>) then any call made to + bankAccounts will be matched. + 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 target(List<String>)will never match a call made + using a variable of type List<Number> (it is not possible for + a type to implement two different parameterizations of the same interface). + If an object might 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 + List<? extends Number> and a call join point with + target pointcut expression target(List<Double>) then + the expression matches but with an unchecked warning. The warning can be suppressed + by annotating the associated advice with either @SuppressAjWarnings + or @SuppressAjWarnings("unchecked"). + + + + When using a parameterized type with the + this pointcut designator then a joinpoint is unambiguously + matched if and only if one or more of the following conditions hold: + + + + the runtime type of the this object extends or + implements the parameterized type. For example, + class Foo implements List<String> will match + this(List<String>). + + The parameterized "this" type is given using a generics wildcard in the pointcut + expression, and the bounds of + the generic runtime type of this are such that all valid parameterizations + are matched by the wildcard. For example, the pointcut expression + this(List<? extends Number>) will match a this + object of type class Foo<N extends Number> implements List<N>, + but not an object of type class Foo<N> implements List<N>. + + + + + You've already seen some examples of using the generic wildcard ? + in parameterized type patterns. Since this, target and + args 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 aList. + + + aList) : + execution(* org.xyz.Foo.*(..)) && args(aList) { + aList.add(new Double(5.0d)); // Compilation error on this line + } ]]> + + Declaring pointcuts in generic classes + + + 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: + + + { + + ... + + // Not allowed - uses T in the pointcut expression + public pointcut fooOperationCall(T t) : + call(* Foo.*(T)) && args(t); + + + // permitted, but recommended to use an alternate variable name in the local + // type variable declaration - e.g. execution(...) + public pointcut fooExecution(Number n) : + execution(* Foo.*(T)) && args(n); + } + ]]> + @@ -1030,8 +1232,8 @@ 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 names do not have to match. For example, given the generic type Foo<T,S extends Number> then: @@ -1048,7 +1250,7 @@ - R Foo<Q, R extends Number>.getMagnitude() {...} + R Foo<Q, R>.getMagnitude() {...} Declares a method getMagnitude on the generic class Foo. The method returns an instance of the type substituted for the second type parameter in an invocation @@ -1058,10 +1260,11 @@ - R Foo<Q, R>.getMagnitude() {...} + R Foo<Q, R extends Number>.getMagnitude() {...} - Results in a compilation error since the generic type Foo with two unbounded - type parameters cannot be found. + 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). @@ -1244,6 +1447,20 @@ * Each child has a parent */ private P C.parent; + + /** + * Parents provide access to their children + */ + public List 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 @@ List<ASTNode> children ASTNode parent + List<ASTNode>getChildren() + ASTNode getParent() void addChild(ASTNode child) void removeChild(ASTNode child) void setParent(ASTNode parent) @@ -1329,6 +1548,7 @@ List<File> children + List<File> getChildren() void addChild(File child) void removeChild(File child) @@ -1337,6 +1557,7 @@ Folder parent + Folder getParent() void setParent(Folder parent) @@ -1359,6 +1580,20 @@ */ private Parent Child.parent; + /** + * Parents provide access to their children + */ + public List 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 */