Repository: tapestry-5
Updated Branches:
  refs/heads/master ebdb52a19 -> faf3b20c9


Revert "TAP5-2453: move GenericsUtils (and tests) to plastic"

This reverts commit 5c617af6b3bfef81d79c573aec0acf29e1d0eb8c.


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/faf3b20c
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/faf3b20c
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/faf3b20c

Branch: refs/heads/master
Commit: faf3b20c9c8f59e890bea4eff5ce8e42df083815
Parents: ebdb52a
Author: Thiago H. de Paula Figueiredo <[email protected]>
Authored: Wed Jan 16 16:06:45 2019 -0200
Committer: Thiago H. de Paula Figueiredo <[email protected]>
Committed: Wed Jan 16 16:06:45 2019 -0200

----------------------------------------------------------------------
 .../ioc/internal/util/GenericsUtils.java        | 643 +++++++++++++++++++
 .../ioc/internal/util/GenericsUtils.java        | 643 -------------------
 .../groovy/ioc/specs/GenericUtilsSpec.groovy    |  40 --
 .../ioc/internal/util/BaseGenericBean.java      |  30 -
 .../ioc/internal/util/NonGenericBean.java       |  30 -
 .../tapestry5/ioc/internal/util/Pair.java       |  42 --
 .../tapestry5/ioc/internal/util/StringBean.java |  20 -
 .../ioc/internal/util/StringLongPair.java       |  19 -
 .../groovy/ioc/specs/GenericUtilsSpec.groovy    |  40 ++
 .../ioc/internal/util/BaseGenericBean.java      |  30 +
 .../ioc/internal/util/NonGenericBean.java       |  30 +
 .../tapestry5/ioc/internal/util/StringBean.java |  20 +
 12 files changed, 763 insertions(+), 824 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git 
a/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
 
b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
new file mode 100644
index 0000000..abbb767
--- /dev/null
+++ 
b/commons/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
@@ -0,0 +1,643 @@
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.util;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.lang.reflect.WildcardType;
+import java.util.ArrayList;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Static methods related to the use of JDK 1.5 generics.
+ */
+@SuppressWarnings("unchecked")
+public class GenericsUtils
+{
+    /**
+     * Analyzes the method in the context of containingClass and returns the 
Class that is represented by
+     * the method's generic return type. Any parameter information in the 
generic return type is lost. If you want
+     * to preserve the type parameters of the return type consider using
+     * {@link #extractActualType(java.lang.reflect.Type, 
java.lang.reflect.Method)}.
+     *
+     * @param containingClass class which either contains or inherited the 
method
+     * @param method          method from which to extract the return type
+     * @return the class represented by the methods generic return type, 
resolved based on the context .
+     * @see #extractActualType(java.lang.reflect.Type, 
java.lang.reflect.Method)
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     * @see #asClass(java.lang.reflect.Type)
+     */
+    public static Class<?> extractGenericReturnType(Class<?> containingClass, 
Method method)
+    {
+        return asClass(resolve(method.getGenericReturnType(), 
containingClass));
+    }
+
+
+    /**
+     * Analyzes the field in the context of containingClass and returns the 
Class that is represented by
+     * the field's generic type. Any parameter information in the generic type 
is lost, if you want
+     * to preserve the type parameters of the return type consider using
+     * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
+     *
+     * @param containingClass class which either contains or inherited the 
field
+     * @param field           field from which to extract the type
+     * @return the class represented by the field's generic type, resolved 
based on the containingClass.
+     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     * @see #asClass(java.lang.reflect.Type)
+     */
+    public static Class extractGenericFieldType(Class containingClass, Field 
field)
+    {
+        return asClass(resolve(field.getGenericType(), containingClass));
+    }
+
+    /**
+     * Analyzes the method in the context of containingClass and returns the 
Class that is represented by
+     * the method's generic return type. Any parameter information in the 
generic return type is lost.
+     *
+     * @param containingType Type which is/represents the class that either 
contains or inherited the method
+     * @param method         method from which to extract the generic return 
type
+     * @return the generic type represented by the methods generic return 
type, resolved based on the containingType.
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     */
+    public static Type extractActualType(Type containingType, Method method)
+    {
+        return resolve(method.getGenericReturnType(), containingType);
+    }
+
+    /**
+     * Analyzes the method in the context of containingClass and returns the 
Class that is represented by
+     * the method's generic return type. Any parameter information in the 
generic return type is lost.
+     *
+     * @param containingType Type which is/represents the class that either 
contains or inherited the field
+     * @param field          field from which to extract the generic return 
type
+     * @return the generic type represented by the methods generic return 
type, resolved based on the containingType.
+     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
+     */
+    public static Type extractActualType(Type containingType, Field field)
+    {
+        return resolve(field.getGenericType(), containingType);
+    }
+
+    /**
+     * Resolves the type parameter based on the context of the containingType.
+     *
+     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type 
argument resolved form the class
+     * hierarchy. This may be something other than a simple Class if the type 
argument is a ParameterizedType for
+     * instance (e.g. {@code List<E>; List<Map<Long, String>>}, E would be 
returned as a ParameterizedType with the raw
+     * type Map and type arguments Long and String.
+     *
+     *
+     * @param type
+     *          the generic type (ParameterizedType, GenericArrayType, 
WildcardType, TypeVariable) to be resolved
+     * @param containingType
+     *          the type which his
+     * @return
+     *          the type resolved to the best of our ability.
+     * @since 5.2.?
+     */
+    public static Type resolve(final Type type, final Type containingType)
+    {
+        // The type isn't generic. (String, Long, etc)
+        if (type instanceof Class)
+            return type;
+
+        // List<T>, List<String>, List<T extends Number>
+        if (type instanceof ParameterizedType)
+            return resolve((ParameterizedType) type, containingType);
+
+        // T[], List<String>[], List<T>[]
+        if (type instanceof GenericArrayType)
+            return resolve((GenericArrayType) type, containingType);
+
+        // List<? extends T>, List<? extends Object & Comparable & 
Serializable>
+        if (type instanceof WildcardType)
+            return resolve((WildcardType) type, containingType);
+
+        // T
+        if (type instanceof TypeVariable)
+            return resolve((TypeVariable) type, containingType);
+
+        // I'm leaning towards an exception here.
+        return type;
+    }
+
+
+    /**
+     * Determines if the suspected super type is assignable from the suspected 
sub type.
+     *
+     * @param suspectedSuperType
+     *          e.g. {@code GenericDAO<Pet, String>}
+     * @param suspectedSubType
+     *          e.g. {@code PetDAO extends GenericDAO<Pet,String>}
+     * @return
+     *          true if (sourceType)targetClass is a valid cast
+     */
+    public static boolean isAssignableFrom(Type suspectedSuperType, Type 
suspectedSubType)
+    {
+        final Class suspectedSuperClass = asClass(suspectedSuperType);
+        final Class suspectedSubClass = asClass(suspectedSubType);
+
+        // The raw types need to be compatible.
+        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
+        {
+            return false;
+        }
+
+        // From this point we know that the raw types are assignable.
+        // We need to figure out what the generic parameters in the 
targetClass are
+        // as they pertain to the sourceType.
+
+        if (suspectedSuperType instanceof WildcardType)
+        {
+            // ? extends Number
+            // needs to match all the bounds (there will only be upper bounds 
or lower bounds
+            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
+            {
+                if (!isAssignableFrom(t, suspectedSubType)) return false;
+            }
+            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
+            {
+                if (!isAssignableFrom(suspectedSubType, t)) return false;
+            }
+            return true;
+        }
+
+        Type curType = suspectedSubType;
+        Class curClass;
+
+        while (curType != null && !curType.equals(Object.class))
+        {
+            curClass = asClass(curType);
+
+            if (curClass.equals(suspectedSuperClass))
+            {
+                final Type resolved = resolve(curType, suspectedSubType);
+
+                if (suspectedSuperType instanceof Class)
+                {
+                    if ( resolved instanceof Class )
+                        return suspectedSuperType.equals(resolved);
+
+                    // They may represent the same class, but the 
suspectedSuperType is not parameterized. The parameter
+                    // types default to Object so they must be a match.
+                    // e.g. Pair p = new StringLongPair();
+                    //      Pair p = new Pair<? extends Number, String>
+
+                    return true;
+                }
+
+                if (suspectedSuperType instanceof ParameterizedType)
+                {
+                    if (resolved instanceof ParameterizedType)
+                    {
+                        final Type[] type1Arguments = ((ParameterizedType) 
suspectedSuperType).getActualTypeArguments();
+                        final Type[] type2Arguments = ((ParameterizedType) 
resolved).getActualTypeArguments();
+                        if (type1Arguments.length != type2Arguments.length) 
return false;
+
+                        for (int i = 0; i < type1Arguments.length; ++i)
+                        {
+                            if (!isAssignableFrom(type1Arguments[i], 
type2Arguments[i])) return false;
+                        }
+                        return true;
+                    }
+                }
+                else if (suspectedSuperType instanceof GenericArrayType)
+                {
+                    if (resolved instanceof GenericArrayType)
+                    {
+                        return isAssignableFrom(
+                                ((GenericArrayType) 
suspectedSuperType).getGenericComponentType(),
+                                ((GenericArrayType) 
resolved).getGenericComponentType()
+                        );
+                    }
+                }
+
+                return false;
+            }
+
+            final Type[] types = curClass.getGenericInterfaces();
+            for (Type t : types)
+            {
+                final Type resolved = resolve(t, suspectedSubType);
+                if (isAssignableFrom(suspectedSuperType, resolved))
+                    return true;
+            }
+
+            curType = curClass.getGenericSuperclass();
+        }
+        return false;
+    }
+
+    /**
+     * Get the class represented by the reflected type.
+     * This method is lossy; You cannot recover the type information from the 
class that is returned.
+     *
+     * {@code TypeVariable} the first bound is returned. If your type variable 
extends multiple interfaces that information
+     * is lost.
+     *
+     * {@code WildcardType} the first lower bound is returned. If the wildcard 
is defined with upper bounds
+     * then {@code Object} is returned.
+     *
+     * @param actualType
+     *           a Class, ParameterizedType, GenericArrayType
+     * @return the un-parameterized class associated with the type.
+     */
+    public static Class asClass(Type actualType)
+    {
+        if (actualType instanceof Class) return (Class) actualType;
+
+        if (actualType instanceof ParameterizedType)
+        {
+            final Type rawType = ((ParameterizedType) actualType).getRawType();
+            // The sun implementation returns getRawType as Class<?>, but 
there is room in the interface for it to be
+            // some other Type. We'll assume it's a Class.
+            // TODO: consider logging or throwing our own exception for that 
day when "something else" causes some confusion
+            return (Class) rawType;
+        }
+
+        if (actualType instanceof GenericArrayType)
+        {
+            final Type type = ((GenericArrayType) 
actualType).getGenericComponentType();
+            return Array.newInstance(asClass(type), 0).getClass();
+        }
+
+        if (actualType instanceof TypeVariable)
+        {
+            // Support for List<T extends Number>
+            // There is always at least one bound. If no bound is specified in 
the source then it will be Object.class
+            return asClass(((TypeVariable) actualType).getBounds()[0]);
+        }
+
+        if (actualType instanceof WildcardType)
+        {
+            final WildcardType wildcardType = (WildcardType) actualType;
+            final Type[] bounds = wildcardType.getLowerBounds();
+            if (bounds != null && bounds.length > 0)
+            {
+                return asClass(bounds[0]);
+            }
+            // If there is no lower bounds then the only thing that makes 
sense is Object.
+            return Object.class;
+        }
+
+        throw new RuntimeException(String.format("Unable to convert %s to 
Class.", actualType));
+    }
+
+    /**
+     * Convert the type into a string. The string representation approximates 
the code that would be used to define the
+     * type.
+     *
+     * @param type - the type.
+     * @return a string representation of the type, similar to how it was 
declared.
+     */
+    public static String toString(Type type)
+    {
+        if ( type instanceof ParameterizedType ) return 
toString((ParameterizedType)type);
+        if ( type instanceof WildcardType ) return 
toString((WildcardType)type);
+        if ( type instanceof GenericArrayType) return 
toString((GenericArrayType)type);
+        if ( type instanceof Class )
+        {
+            final Class theClass = (Class) type;
+            return (theClass.isArray() ? theClass.getName() + "[]" : 
theClass.getName());
+        }
+        return type.toString();
+    }
+
+    /**
+     * Method to resolve a TypeVariable to its most
+     * <a 
href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582";>reifiable</a>
 form.
+     *
+     *
+     * How to resolve a TypeVariable:<br/>
+     * All of the TypeVariables defined by a generic class will be given a 
Type by any class that extends it. The Type
+     * given may or may not be reifiable; it may be another TypeVariable for 
instance.
+     *
+     * Consider <br/>
+     * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
+     * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
+     *
+     * To resolve the actual return type of Pair.getA() you must first resolve 
the TypeVariable "A".
+     * We can do that by first finding the index of "A" in the 
Pair.class.getTypeParameters() array of TypeVariables.
+     *
+     * To get to the Type provided by StringLongPair you access the generics 
information by calling
+     * StringLongPair.class.getGenericSuperclass; this will be a 
ParameterizedType. ParameterizedType gives you access
+     * to the actual type arguments provided to Pair by StringLongPair. The 
array is in the same order as the array in
+     * Pair.class.getTypeParameters so you can use the index we discovered 
earlier to extract the Type; String.class.
+     *
+     * When extracting Types we only have to consider the superclass hierarchy 
and not the interfaces implemented by
+     * the class. When a class implements a generic interface it must provide 
types for the interface and any generic
+     * methods implemented from the interface will be re-defined by the class 
with its generic type variables.
+     *
+     * @param typeVariable   - the type variable to resolve.
+     * @param containingType - the shallowest class in the class hierarchy 
(furthest from Object) where typeVariable is defined.
+     * @return a Type that has had all possible TypeVariables resolved that 
have been defined between the type variable
+     *         declaration and the containingType.
+     */
+    private static Type resolve(TypeVariable typeVariable, Type containingType)
+    {
+        // The generic declaration is either a Class, Method or Constructor
+        final GenericDeclaration genericDeclaration = 
typeVariable.getGenericDeclaration();
+
+        if (!(genericDeclaration instanceof Class))
+        {
+            // It's a method or constructor. The best we can do here is try to 
resolve the bounds
+            // e.g. <T extends E> T getT(T param){} where E is defined by the 
class.
+            final Type bounds0 = typeVariable.getBounds()[0];
+            return resolve(bounds0, containingType);
+        }
+
+        final Class typeVariableOwner = (Class) genericDeclaration;
+
+        // find the typeOwner in the containingType's hierarchy
+        final LinkedList<Type> stack = new LinkedList<Type>();
+
+        // If you pass a List<Long> as the containingType then the 
TypeVariable is going to be resolved by the
+        // containingType and not the super class.
+        if (containingType instanceof ParameterizedType)
+        {
+            stack.add(containingType);
+        }
+
+        Class theClass = asClass(containingType);
+        addGenericSuperclasses(theClass, typeVariableOwner, stack);
+
+        int i = getTypeVariableIndex(typeVariable);
+        Type resolved = typeVariable;
+        for (Type t : stack)
+        {
+            if (t instanceof ParameterizedType)
+            {
+                resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
+                if (resolved instanceof Class) return resolved;
+                if (resolved instanceof TypeVariable)
+                {
+                    // Need to look at the next class in the hierarchy
+                    i = getTypeVariableIndex((TypeVariable) resolved);
+                    continue;
+                }
+                return resolve(resolved, containingType);
+            }
+        }
+
+        // the only way we get here is if resolved is still a TypeVariable, 
otherwise an
+        // exception is thrown or a value is returned.
+        return ((TypeVariable) resolved).getBounds()[0];
+    }
+
+
+    private static void addGenericSuperclasses(Class theClass, final Class 
typeVariableOwner, final LinkedList<Type> stack) {
+        Type genericSuperclass = theClass.getGenericSuperclass();
+        while (genericSuperclass != null && // true for interfaces with no 
superclass
+                !theClass.equals(Object.class) &&
+                !theClass.equals(typeVariableOwner))
+        {
+            stack.addFirst(genericSuperclass);
+            theClass = asClass(genericSuperclass);
+            genericSuperclass = theClass.getGenericSuperclass();
+        }
+        for (Type type : theClass.getGenericInterfaces()) {
+            stack.add(type);
+        }
+        for (Class implementedInterface : 
getAllImplementedInterfaces(theClass)) {
+            addGenericSuperclasses(implementedInterface, typeVariableOwner, 
stack);
+        }
+    }
+    
+    private static List<Class> getAllImplementedInterfaces(Class theClass) {
+        List<Class> list = new ArrayList<>();
+        for (Class implementedInterface : theClass.getInterfaces()) {
+            list.add(implementedInterface);
+            list.addAll(getAllImplementedInterfaces(implementedInterface));
+        }
+        return list;
+    }
+
+    /**
+     * @param type           - something like List&lt;T>[] or List&lt;? 
extends T>[] or T[]
+     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
+     * @return either the passed type if no changes required or a copy with a 
best effort resolve of the component type.
+     */
+    private static GenericArrayType resolve(GenericArrayType type, Type 
containingType)
+    {
+        final Type componentType = type.getGenericComponentType();
+
+        if (!(componentType instanceof Class))
+        {
+            final Type resolved = resolve(componentType, containingType);
+            return create(resolved);
+        }
+
+        return type;
+    }
+
+    /**
+     * @param type           - something like List&lt;T>, List&lt;T extends 
Number>
+     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
+     * @return the passed type if nothing to resolve or a copy of the type 
with the type arguments resolved.
+     */
+    private static ParameterizedType resolve(ParameterizedType type, Type 
containingType)
+    {
+        // Use a copy because we're going to modify it.
+        final Type[] types = type.getActualTypeArguments().clone();
+
+        boolean modified = resolve(types, containingType);
+        return modified ? create(type.getRawType(), type.getOwnerType(), 
types) : type;
+    }
+
+    /**
+     * @param type           - something like List&lt;? super T>, List<&lt;? 
extends T>, List&lt;? extends T & Comparable&lt? super T>>
+     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
+     * @return the passed type if nothing to resolve or a copy of the type 
with the upper and lower bounds resolved.
+     */
+    private static WildcardType resolve(WildcardType type, Type containingType)
+    {
+        // Use a copy because we're going to modify them.
+        final Type[] upper = type.getUpperBounds().clone();
+        final Type[] lower = type.getLowerBounds().clone();
+
+        boolean modified = resolve(upper, containingType);
+        modified = modified || resolve(lower, containingType);
+
+        return modified ? create(upper, lower) : type;
+    }
+
+    /**
+     * @param types          - Array of types to resolve. The unresolved type 
is replaced in the array with the resolved type.
+     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
+     * @return true if any of the types were resolved.
+     */
+    private static boolean resolve(Type[] types, Type containingType)
+    {
+        boolean modified = false;
+        for (int i = 0; i < types.length; ++i)
+        {
+            Type t = types[i];
+            if (!(t instanceof Class))
+            {
+                modified = true;
+                final Type resolved = resolve(t, containingType);
+                if (!resolved.equals(t))
+                {
+                    types[i] = resolved;
+                    modified = true;
+                }
+            }
+        }
+        return modified;
+    }
+
+    /**
+     * @param rawType       - the un-parameterized type.
+     * @param ownerType     - the outer class or null if the class is not 
defined within another class.
+     * @param typeArguments - type arguments.
+     * @return a copy of the type with the typeArguments replaced.
+     */
+    static ParameterizedType create(final Type rawType, final Type ownerType, 
final Type[] typeArguments)
+    {
+        return new ParameterizedType()
+        {
+            @Override
+            public Type[] getActualTypeArguments()
+            {
+                return typeArguments;
+            }
+
+            @Override
+            public Type getRawType()
+            {
+                return rawType;
+            }
+
+            @Override
+            public Type getOwnerType()
+            {
+                return ownerType;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    static GenericArrayType create(final Type componentType)
+    {
+        return new GenericArrayType()
+        {
+            @Override
+            public Type getGenericComponentType()
+            {
+                return componentType;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    /**
+     * @param upperBounds - e.g. ? extends Number
+     * @param lowerBounds - e.g. ? super Long
+     * @return An new copy of the type with the upper and lower bounds 
replaced.
+     */
+    static WildcardType create(final Type[] upperBounds, final Type[] 
lowerBounds)
+    {
+
+        return new WildcardType()
+        {
+            @Override
+            public Type[] getUpperBounds()
+            {
+                return upperBounds;
+            }
+
+            @Override
+            public Type[] getLowerBounds()
+            {
+                return lowerBounds;
+            }
+
+            @Override
+            public String toString()
+            {
+                return GenericsUtils.toString(this);
+            }
+        };
+    }
+
+    static String toString(ParameterizedType pt)
+    {
+        String s = toString(pt.getActualTypeArguments());
+        return String.format("%s<%s>", toString(pt.getRawType()), s);
+    }
+
+    static String toString(GenericArrayType gat)
+    {
+        return String.format("%s[]", toString(gat.getGenericComponentType()));
+    }
+
+    static String toString(WildcardType wt)
+    {
+        final boolean isSuper = wt.getLowerBounds().length > 0;
+        return String.format("? %s %s",
+                isSuper ? "super" : "extends",
+                toString(wt.getLowerBounds()));
+    }
+
+    static String toString(Type[] types)
+    {
+        StringBuilder sb = new StringBuilder();
+        for ( Type t : types )
+        {
+            sb.append(toString(t)).append(", ");
+        }
+        return sb.substring(0, sb.length() - 2);// drop last ,
+    }
+
+    /**
+     * Find the index of the TypeVariable in the classes parameters. The 
offset can be used on a subclass to find
+     * the actual type.
+     *
+     * @param typeVariable - the type variable in question.
+     * @return the index of the type variable in its declaring 
class/method/constructor's type parameters.
+     */
+    private static int getTypeVariableIndex(final TypeVariable typeVariable)
+    {
+        // the label from the class (the T in List<T>, the K or V in Map<K,V>, 
etc)
+        final String typeVarName = typeVariable.getName();
+        final TypeVariable[] typeParameters = 
typeVariable.getGenericDeclaration().getTypeParameters();
+        for (int typeArgumentIndex = 0; typeArgumentIndex < 
typeParameters.length; typeArgumentIndex++)
+        {
+            // The .equals for TypeVariable may not be compatible, a name 
check should be sufficient.
+            if 
(typeParameters[typeArgumentIndex].getName().equals(typeVarName))
+                return typeArgumentIndex;
+        }
+
+        // The only way this could happen is if the TypeVariable is hand built 
incorrectly, or it's corrupted.
+        throw new RuntimeException(
+                String.format("%s does not have a TypeVariable matching %s", 
typeVariable.getGenericDeclaration(), typeVariable));
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
 
b/plastic/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
deleted file mode 100644
index abbb767..0000000
--- 
a/plastic/src/main/java/org/apache/tapestry5/ioc/internal/util/GenericsUtils.java
+++ /dev/null
@@ -1,643 +0,0 @@
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.util;
-
-import java.lang.reflect.Array;
-import java.lang.reflect.Field;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.GenericDeclaration;
-import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.lang.reflect.TypeVariable;
-import java.lang.reflect.WildcardType;
-import java.util.ArrayList;
-import java.util.LinkedList;
-import java.util.List;
-
-/**
- * Static methods related to the use of JDK 1.5 generics.
- */
-@SuppressWarnings("unchecked")
-public class GenericsUtils
-{
-    /**
-     * Analyzes the method in the context of containingClass and returns the 
Class that is represented by
-     * the method's generic return type. Any parameter information in the 
generic return type is lost. If you want
-     * to preserve the type parameters of the return type consider using
-     * {@link #extractActualType(java.lang.reflect.Type, 
java.lang.reflect.Method)}.
-     *
-     * @param containingClass class which either contains or inherited the 
method
-     * @param method          method from which to extract the return type
-     * @return the class represented by the methods generic return type, 
resolved based on the context .
-     * @see #extractActualType(java.lang.reflect.Type, 
java.lang.reflect.Method)
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     * @see #asClass(java.lang.reflect.Type)
-     */
-    public static Class<?> extractGenericReturnType(Class<?> containingClass, 
Method method)
-    {
-        return asClass(resolve(method.getGenericReturnType(), 
containingClass));
-    }
-
-
-    /**
-     * Analyzes the field in the context of containingClass and returns the 
Class that is represented by
-     * the field's generic type. Any parameter information in the generic type 
is lost, if you want
-     * to preserve the type parameters of the return type consider using
-     * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
-     *
-     * @param containingClass class which either contains or inherited the 
field
-     * @param field           field from which to extract the type
-     * @return the class represented by the field's generic type, resolved 
based on the containingClass.
-     * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     * @see #asClass(java.lang.reflect.Type)
-     */
-    public static Class extractGenericFieldType(Class containingClass, Field 
field)
-    {
-        return asClass(resolve(field.getGenericType(), containingClass));
-    }
-
-    /**
-     * Analyzes the method in the context of containingClass and returns the 
Class that is represented by
-     * the method's generic return type. Any parameter information in the 
generic return type is lost.
-     *
-     * @param containingType Type which is/represents the class that either 
contains or inherited the method
-     * @param method         method from which to extract the generic return 
type
-     * @return the generic type represented by the methods generic return 
type, resolved based on the containingType.
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     */
-    public static Type extractActualType(Type containingType, Method method)
-    {
-        return resolve(method.getGenericReturnType(), containingType);
-    }
-
-    /**
-     * Analyzes the method in the context of containingClass and returns the 
Class that is represented by
-     * the method's generic return type. Any parameter information in the 
generic return type is lost.
-     *
-     * @param containingType Type which is/represents the class that either 
contains or inherited the field
-     * @param field          field from which to extract the generic return 
type
-     * @return the generic type represented by the methods generic return 
type, resolved based on the containingType.
-     * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
-     */
-    public static Type extractActualType(Type containingType, Field field)
-    {
-        return resolve(field.getGenericType(), containingType);
-    }
-
-    /**
-     * Resolves the type parameter based on the context of the containingType.
-     *
-     * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type 
argument resolved form the class
-     * hierarchy. This may be something other than a simple Class if the type 
argument is a ParameterizedType for
-     * instance (e.g. {@code List<E>; List<Map<Long, String>>}, E would be 
returned as a ParameterizedType with the raw
-     * type Map and type arguments Long and String.
-     *
-     *
-     * @param type
-     *          the generic type (ParameterizedType, GenericArrayType, 
WildcardType, TypeVariable) to be resolved
-     * @param containingType
-     *          the type which his
-     * @return
-     *          the type resolved to the best of our ability.
-     * @since 5.2.?
-     */
-    public static Type resolve(final Type type, final Type containingType)
-    {
-        // The type isn't generic. (String, Long, etc)
-        if (type instanceof Class)
-            return type;
-
-        // List<T>, List<String>, List<T extends Number>
-        if (type instanceof ParameterizedType)
-            return resolve((ParameterizedType) type, containingType);
-
-        // T[], List<String>[], List<T>[]
-        if (type instanceof GenericArrayType)
-            return resolve((GenericArrayType) type, containingType);
-
-        // List<? extends T>, List<? extends Object & Comparable & 
Serializable>
-        if (type instanceof WildcardType)
-            return resolve((WildcardType) type, containingType);
-
-        // T
-        if (type instanceof TypeVariable)
-            return resolve((TypeVariable) type, containingType);
-
-        // I'm leaning towards an exception here.
-        return type;
-    }
-
-
-    /**
-     * Determines if the suspected super type is assignable from the suspected 
sub type.
-     *
-     * @param suspectedSuperType
-     *          e.g. {@code GenericDAO<Pet, String>}
-     * @param suspectedSubType
-     *          e.g. {@code PetDAO extends GenericDAO<Pet,String>}
-     * @return
-     *          true if (sourceType)targetClass is a valid cast
-     */
-    public static boolean isAssignableFrom(Type suspectedSuperType, Type 
suspectedSubType)
-    {
-        final Class suspectedSuperClass = asClass(suspectedSuperType);
-        final Class suspectedSubClass = asClass(suspectedSubType);
-
-        // The raw types need to be compatible.
-        if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
-        {
-            return false;
-        }
-
-        // From this point we know that the raw types are assignable.
-        // We need to figure out what the generic parameters in the 
targetClass are
-        // as they pertain to the sourceType.
-
-        if (suspectedSuperType instanceof WildcardType)
-        {
-            // ? extends Number
-            // needs to match all the bounds (there will only be upper bounds 
or lower bounds
-            for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
-            {
-                if (!isAssignableFrom(t, suspectedSubType)) return false;
-            }
-            for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
-            {
-                if (!isAssignableFrom(suspectedSubType, t)) return false;
-            }
-            return true;
-        }
-
-        Type curType = suspectedSubType;
-        Class curClass;
-
-        while (curType != null && !curType.equals(Object.class))
-        {
-            curClass = asClass(curType);
-
-            if (curClass.equals(suspectedSuperClass))
-            {
-                final Type resolved = resolve(curType, suspectedSubType);
-
-                if (suspectedSuperType instanceof Class)
-                {
-                    if ( resolved instanceof Class )
-                        return suspectedSuperType.equals(resolved);
-
-                    // They may represent the same class, but the 
suspectedSuperType is not parameterized. The parameter
-                    // types default to Object so they must be a match.
-                    // e.g. Pair p = new StringLongPair();
-                    //      Pair p = new Pair<? extends Number, String>
-
-                    return true;
-                }
-
-                if (suspectedSuperType instanceof ParameterizedType)
-                {
-                    if (resolved instanceof ParameterizedType)
-                    {
-                        final Type[] type1Arguments = ((ParameterizedType) 
suspectedSuperType).getActualTypeArguments();
-                        final Type[] type2Arguments = ((ParameterizedType) 
resolved).getActualTypeArguments();
-                        if (type1Arguments.length != type2Arguments.length) 
return false;
-
-                        for (int i = 0; i < type1Arguments.length; ++i)
-                        {
-                            if (!isAssignableFrom(type1Arguments[i], 
type2Arguments[i])) return false;
-                        }
-                        return true;
-                    }
-                }
-                else if (suspectedSuperType instanceof GenericArrayType)
-                {
-                    if (resolved instanceof GenericArrayType)
-                    {
-                        return isAssignableFrom(
-                                ((GenericArrayType) 
suspectedSuperType).getGenericComponentType(),
-                                ((GenericArrayType) 
resolved).getGenericComponentType()
-                        );
-                    }
-                }
-
-                return false;
-            }
-
-            final Type[] types = curClass.getGenericInterfaces();
-            for (Type t : types)
-            {
-                final Type resolved = resolve(t, suspectedSubType);
-                if (isAssignableFrom(suspectedSuperType, resolved))
-                    return true;
-            }
-
-            curType = curClass.getGenericSuperclass();
-        }
-        return false;
-    }
-
-    /**
-     * Get the class represented by the reflected type.
-     * This method is lossy; You cannot recover the type information from the 
class that is returned.
-     *
-     * {@code TypeVariable} the first bound is returned. If your type variable 
extends multiple interfaces that information
-     * is lost.
-     *
-     * {@code WildcardType} the first lower bound is returned. If the wildcard 
is defined with upper bounds
-     * then {@code Object} is returned.
-     *
-     * @param actualType
-     *           a Class, ParameterizedType, GenericArrayType
-     * @return the un-parameterized class associated with the type.
-     */
-    public static Class asClass(Type actualType)
-    {
-        if (actualType instanceof Class) return (Class) actualType;
-
-        if (actualType instanceof ParameterizedType)
-        {
-            final Type rawType = ((ParameterizedType) actualType).getRawType();
-            // The sun implementation returns getRawType as Class<?>, but 
there is room in the interface for it to be
-            // some other Type. We'll assume it's a Class.
-            // TODO: consider logging or throwing our own exception for that 
day when "something else" causes some confusion
-            return (Class) rawType;
-        }
-
-        if (actualType instanceof GenericArrayType)
-        {
-            final Type type = ((GenericArrayType) 
actualType).getGenericComponentType();
-            return Array.newInstance(asClass(type), 0).getClass();
-        }
-
-        if (actualType instanceof TypeVariable)
-        {
-            // Support for List<T extends Number>
-            // There is always at least one bound. If no bound is specified in 
the source then it will be Object.class
-            return asClass(((TypeVariable) actualType).getBounds()[0]);
-        }
-
-        if (actualType instanceof WildcardType)
-        {
-            final WildcardType wildcardType = (WildcardType) actualType;
-            final Type[] bounds = wildcardType.getLowerBounds();
-            if (bounds != null && bounds.length > 0)
-            {
-                return asClass(bounds[0]);
-            }
-            // If there is no lower bounds then the only thing that makes 
sense is Object.
-            return Object.class;
-        }
-
-        throw new RuntimeException(String.format("Unable to convert %s to 
Class.", actualType));
-    }
-
-    /**
-     * Convert the type into a string. The string representation approximates 
the code that would be used to define the
-     * type.
-     *
-     * @param type - the type.
-     * @return a string representation of the type, similar to how it was 
declared.
-     */
-    public static String toString(Type type)
-    {
-        if ( type instanceof ParameterizedType ) return 
toString((ParameterizedType)type);
-        if ( type instanceof WildcardType ) return 
toString((WildcardType)type);
-        if ( type instanceof GenericArrayType) return 
toString((GenericArrayType)type);
-        if ( type instanceof Class )
-        {
-            final Class theClass = (Class) type;
-            return (theClass.isArray() ? theClass.getName() + "[]" : 
theClass.getName());
-        }
-        return type.toString();
-    }
-
-    /**
-     * Method to resolve a TypeVariable to its most
-     * <a 
href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582";>reifiable</a>
 form.
-     *
-     *
-     * How to resolve a TypeVariable:<br/>
-     * All of the TypeVariables defined by a generic class will be given a 
Type by any class that extends it. The Type
-     * given may or may not be reifiable; it may be another TypeVariable for 
instance.
-     *
-     * Consider <br/>
-     * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
-     * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
-     *
-     * To resolve the actual return type of Pair.getA() you must first resolve 
the TypeVariable "A".
-     * We can do that by first finding the index of "A" in the 
Pair.class.getTypeParameters() array of TypeVariables.
-     *
-     * To get to the Type provided by StringLongPair you access the generics 
information by calling
-     * StringLongPair.class.getGenericSuperclass; this will be a 
ParameterizedType. ParameterizedType gives you access
-     * to the actual type arguments provided to Pair by StringLongPair. The 
array is in the same order as the array in
-     * Pair.class.getTypeParameters so you can use the index we discovered 
earlier to extract the Type; String.class.
-     *
-     * When extracting Types we only have to consider the superclass hierarchy 
and not the interfaces implemented by
-     * the class. When a class implements a generic interface it must provide 
types for the interface and any generic
-     * methods implemented from the interface will be re-defined by the class 
with its generic type variables.
-     *
-     * @param typeVariable   - the type variable to resolve.
-     * @param containingType - the shallowest class in the class hierarchy 
(furthest from Object) where typeVariable is defined.
-     * @return a Type that has had all possible TypeVariables resolved that 
have been defined between the type variable
-     *         declaration and the containingType.
-     */
-    private static Type resolve(TypeVariable typeVariable, Type containingType)
-    {
-        // The generic declaration is either a Class, Method or Constructor
-        final GenericDeclaration genericDeclaration = 
typeVariable.getGenericDeclaration();
-
-        if (!(genericDeclaration instanceof Class))
-        {
-            // It's a method or constructor. The best we can do here is try to 
resolve the bounds
-            // e.g. <T extends E> T getT(T param){} where E is defined by the 
class.
-            final Type bounds0 = typeVariable.getBounds()[0];
-            return resolve(bounds0, containingType);
-        }
-
-        final Class typeVariableOwner = (Class) genericDeclaration;
-
-        // find the typeOwner in the containingType's hierarchy
-        final LinkedList<Type> stack = new LinkedList<Type>();
-
-        // If you pass a List<Long> as the containingType then the 
TypeVariable is going to be resolved by the
-        // containingType and not the super class.
-        if (containingType instanceof ParameterizedType)
-        {
-            stack.add(containingType);
-        }
-
-        Class theClass = asClass(containingType);
-        addGenericSuperclasses(theClass, typeVariableOwner, stack);
-
-        int i = getTypeVariableIndex(typeVariable);
-        Type resolved = typeVariable;
-        for (Type t : stack)
-        {
-            if (t instanceof ParameterizedType)
-            {
-                resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
-                if (resolved instanceof Class) return resolved;
-                if (resolved instanceof TypeVariable)
-                {
-                    // Need to look at the next class in the hierarchy
-                    i = getTypeVariableIndex((TypeVariable) resolved);
-                    continue;
-                }
-                return resolve(resolved, containingType);
-            }
-        }
-
-        // the only way we get here is if resolved is still a TypeVariable, 
otherwise an
-        // exception is thrown or a value is returned.
-        return ((TypeVariable) resolved).getBounds()[0];
-    }
-
-
-    private static void addGenericSuperclasses(Class theClass, final Class 
typeVariableOwner, final LinkedList<Type> stack) {
-        Type genericSuperclass = theClass.getGenericSuperclass();
-        while (genericSuperclass != null && // true for interfaces with no 
superclass
-                !theClass.equals(Object.class) &&
-                !theClass.equals(typeVariableOwner))
-        {
-            stack.addFirst(genericSuperclass);
-            theClass = asClass(genericSuperclass);
-            genericSuperclass = theClass.getGenericSuperclass();
-        }
-        for (Type type : theClass.getGenericInterfaces()) {
-            stack.add(type);
-        }
-        for (Class implementedInterface : 
getAllImplementedInterfaces(theClass)) {
-            addGenericSuperclasses(implementedInterface, typeVariableOwner, 
stack);
-        }
-    }
-    
-    private static List<Class> getAllImplementedInterfaces(Class theClass) {
-        List<Class> list = new ArrayList<>();
-        for (Class implementedInterface : theClass.getInterfaces()) {
-            list.add(implementedInterface);
-            list.addAll(getAllImplementedInterfaces(implementedInterface));
-        }
-        return list;
-    }
-
-    /**
-     * @param type           - something like List&lt;T>[] or List&lt;? 
extends T>[] or T[]
-     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
-     * @return either the passed type if no changes required or a copy with a 
best effort resolve of the component type.
-     */
-    private static GenericArrayType resolve(GenericArrayType type, Type 
containingType)
-    {
-        final Type componentType = type.getGenericComponentType();
-
-        if (!(componentType instanceof Class))
-        {
-            final Type resolved = resolve(componentType, containingType);
-            return create(resolved);
-        }
-
-        return type;
-    }
-
-    /**
-     * @param type           - something like List&lt;T>, List&lt;T extends 
Number>
-     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
-     * @return the passed type if nothing to resolve or a copy of the type 
with the type arguments resolved.
-     */
-    private static ParameterizedType resolve(ParameterizedType type, Type 
containingType)
-    {
-        // Use a copy because we're going to modify it.
-        final Type[] types = type.getActualTypeArguments().clone();
-
-        boolean modified = resolve(types, containingType);
-        return modified ? create(type.getRawType(), type.getOwnerType(), 
types) : type;
-    }
-
-    /**
-     * @param type           - something like List&lt;? super T>, List<&lt;? 
extends T>, List&lt;? extends T & Comparable&lt? super T>>
-     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
-     * @return the passed type if nothing to resolve or a copy of the type 
with the upper and lower bounds resolved.
-     */
-    private static WildcardType resolve(WildcardType type, Type containingType)
-    {
-        // Use a copy because we're going to modify them.
-        final Type[] upper = type.getUpperBounds().clone();
-        final Type[] lower = type.getLowerBounds().clone();
-
-        boolean modified = resolve(upper, containingType);
-        modified = modified || resolve(lower, containingType);
-
-        return modified ? create(upper, lower) : type;
-    }
-
-    /**
-     * @param types          - Array of types to resolve. The unresolved type 
is replaced in the array with the resolved type.
-     * @param containingType - the shallowest type in the hierarchy where type 
is defined.
-     * @return true if any of the types were resolved.
-     */
-    private static boolean resolve(Type[] types, Type containingType)
-    {
-        boolean modified = false;
-        for (int i = 0; i < types.length; ++i)
-        {
-            Type t = types[i];
-            if (!(t instanceof Class))
-            {
-                modified = true;
-                final Type resolved = resolve(t, containingType);
-                if (!resolved.equals(t))
-                {
-                    types[i] = resolved;
-                    modified = true;
-                }
-            }
-        }
-        return modified;
-    }
-
-    /**
-     * @param rawType       - the un-parameterized type.
-     * @param ownerType     - the outer class or null if the class is not 
defined within another class.
-     * @param typeArguments - type arguments.
-     * @return a copy of the type with the typeArguments replaced.
-     */
-    static ParameterizedType create(final Type rawType, final Type ownerType, 
final Type[] typeArguments)
-    {
-        return new ParameterizedType()
-        {
-            @Override
-            public Type[] getActualTypeArguments()
-            {
-                return typeArguments;
-            }
-
-            @Override
-            public Type getRawType()
-            {
-                return rawType;
-            }
-
-            @Override
-            public Type getOwnerType()
-            {
-                return ownerType;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    static GenericArrayType create(final Type componentType)
-    {
-        return new GenericArrayType()
-        {
-            @Override
-            public Type getGenericComponentType()
-            {
-                return componentType;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    /**
-     * @param upperBounds - e.g. ? extends Number
-     * @param lowerBounds - e.g. ? super Long
-     * @return An new copy of the type with the upper and lower bounds 
replaced.
-     */
-    static WildcardType create(final Type[] upperBounds, final Type[] 
lowerBounds)
-    {
-
-        return new WildcardType()
-        {
-            @Override
-            public Type[] getUpperBounds()
-            {
-                return upperBounds;
-            }
-
-            @Override
-            public Type[] getLowerBounds()
-            {
-                return lowerBounds;
-            }
-
-            @Override
-            public String toString()
-            {
-                return GenericsUtils.toString(this);
-            }
-        };
-    }
-
-    static String toString(ParameterizedType pt)
-    {
-        String s = toString(pt.getActualTypeArguments());
-        return String.format("%s<%s>", toString(pt.getRawType()), s);
-    }
-
-    static String toString(GenericArrayType gat)
-    {
-        return String.format("%s[]", toString(gat.getGenericComponentType()));
-    }
-
-    static String toString(WildcardType wt)
-    {
-        final boolean isSuper = wt.getLowerBounds().length > 0;
-        return String.format("? %s %s",
-                isSuper ? "super" : "extends",
-                toString(wt.getLowerBounds()));
-    }
-
-    static String toString(Type[] types)
-    {
-        StringBuilder sb = new StringBuilder();
-        for ( Type t : types )
-        {
-            sb.append(toString(t)).append(", ");
-        }
-        return sb.substring(0, sb.length() - 2);// drop last ,
-    }
-
-    /**
-     * Find the index of the TypeVariable in the classes parameters. The 
offset can be used on a subclass to find
-     * the actual type.
-     *
-     * @param typeVariable - the type variable in question.
-     * @return the index of the type variable in its declaring 
class/method/constructor's type parameters.
-     */
-    private static int getTypeVariableIndex(final TypeVariable typeVariable)
-    {
-        // the label from the class (the T in List<T>, the K or V in Map<K,V>, 
etc)
-        final String typeVarName = typeVariable.getName();
-        final TypeVariable[] typeParameters = 
typeVariable.getGenericDeclaration().getTypeParameters();
-        for (int typeArgumentIndex = 0; typeArgumentIndex < 
typeParameters.length; typeArgumentIndex++)
-        {
-            // The .equals for TypeVariable may not be compatible, a name 
check should be sufficient.
-            if 
(typeParameters[typeArgumentIndex].getName().equals(typeVarName))
-                return typeArgumentIndex;
-        }
-
-        // The only way this could happen is if the TypeVariable is hand built 
incorrectly, or it's corrupted.
-        throw new RuntimeException(
-                String.format("%s does not have a TypeVariable matching %s", 
typeVariable.getGenericDeclaration(), typeVariable));
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy
----------------------------------------------------------------------
diff --git a/plastic/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy 
b/plastic/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy
deleted file mode 100644
index 6b527d2..0000000
--- a/plastic/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy
+++ /dev/null
@@ -1,40 +0,0 @@
-package ioc.specs
-
-import org.apache.tapestry5.ioc.internal.util.GenericsUtils
-import org.apache.tapestry5.ioc.internal.util.NonGenericBean
-import org.apache.tapestry5.ioc.internal.util.StringBean
-import org.apache.tapestry5.ioc.internal.util.StringLongPair
-import spock.lang.Specification
-import spock.lang.Unroll
-
-class GenericUtilsSpec extends Specification {
-
-  def find(clazz, name) {
-    def method = clazz.methods.find { it.name.equalsIgnoreCase(name) }
-
-    if (method == null) {
-      throw new IllegalArgumentException("Unable to find method '$name' of 
${clazz.name}.")
-    }
-
-    return method
-  }
-
-  @Unroll
-  def "generic return type for #method is #expected"() {
-
-    expect:
-
-    GenericsUtils.extractGenericReturnType(clazz, method).is(expected)
-
-    where:
-
-    clazz          | name       | expected
-    NonGenericBean | "getvalue" | String
-    StringBean     | "getvalue" | String
-    StringLongPair | "getkey"   | String
-    StringLongPair | "getvalue" | Long
-
-    method = find(clazz, name)
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
 
b/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
deleted file mode 100644
index dc4c2c7..0000000
--- 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2008 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.util;
-
-public class BaseGenericBean<T>
-{
-    private T value;
-
-    public T getValue()
-    {
-        return value;
-    }
-
-    public void setValue(T value)
-    {
-        this.value = value;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
 
b/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
deleted file mode 100644
index 8cce49f..0000000
--- 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright 2008 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.util;
-
-public class NonGenericBean
-{
-    private String value;
-
-    public String getValue()
-    {
-        return value;
-    }
-
-    public void setValue(String value)
-    {
-        this.value = value;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/Pair.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/Pair.java 
b/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/Pair.java
deleted file mode 100644
index 00722f4..0000000
--- a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/Pair.java
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2008 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.util;
-
-public class Pair<K, V>
-{
-    private K key;
-
-    private V value;
-
-    public K getKey()
-    {
-        return key;
-    }
-
-    public void setKey(K key)
-    {
-        this.key = key;
-    }
-
-    public V getValue()
-    {
-        return value;
-    }
-
-    public void setValue(V value)
-    {
-        this.value = value;
-    }
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java 
b/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
deleted file mode 100644
index 1b13856..0000000
--- 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright 2008 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.util;
-
-public class StringBean extends BaseGenericBean<String>
-{
-
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringLongPair.java
----------------------------------------------------------------------
diff --git 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringLongPair.java
 
b/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringLongPair.java
deleted file mode 100644
index 0071beb..0000000
--- 
a/plastic/src/test/java/org/apache/tapestry5/ioc/internal/util/StringLongPair.java
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2008 The Apache Software Foundation
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package org.apache.tapestry5.ioc.internal.util;
-
-public class StringLongPair extends Pair<String, Long>
-{
-}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/tapestry-ioc/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy
----------------------------------------------------------------------
diff --git a/tapestry-ioc/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy 
b/tapestry-ioc/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy
new file mode 100644
index 0000000..6b527d2
--- /dev/null
+++ b/tapestry-ioc/src/test/groovy/ioc/specs/GenericUtilsSpec.groovy
@@ -0,0 +1,40 @@
+package ioc.specs
+
+import org.apache.tapestry5.ioc.internal.util.GenericsUtils
+import org.apache.tapestry5.ioc.internal.util.NonGenericBean
+import org.apache.tapestry5.ioc.internal.util.StringBean
+import org.apache.tapestry5.ioc.internal.util.StringLongPair
+import spock.lang.Specification
+import spock.lang.Unroll
+
+class GenericUtilsSpec extends Specification {
+
+  def find(clazz, name) {
+    def method = clazz.methods.find { it.name.equalsIgnoreCase(name) }
+
+    if (method == null) {
+      throw new IllegalArgumentException("Unable to find method '$name' of 
${clazz.name}.")
+    }
+
+    return method
+  }
+
+  @Unroll
+  def "generic return type for #method is #expected"() {
+
+    expect:
+
+    GenericsUtils.extractGenericReturnType(clazz, method).is(expected)
+
+    where:
+
+    clazz          | name       | expected
+    NonGenericBean | "getvalue" | String
+    StringBean     | "getvalue" | String
+    StringLongPair | "getkey"   | String
+    StringLongPair | "getvalue" | Long
+
+    method = find(clazz, name)
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
new file mode 100644
index 0000000..dc4c2c7
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/BaseGenericBean.java
@@ -0,0 +1,30 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.util;
+
+public class BaseGenericBean<T>
+{
+    private T value;
+
+    public T getValue()
+    {
+        return value;
+    }
+
+    public void setValue(T value)
+    {
+        this.value = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
new file mode 100644
index 0000000..8cce49f
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/NonGenericBean.java
@@ -0,0 +1,30 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.util;
+
+public class NonGenericBean
+{
+    private String value;
+
+    public String getValue()
+    {
+        return value;
+    }
+
+    public void setValue(String value)
+    {
+        this.value = value;
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/faf3b20c/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
----------------------------------------------------------------------
diff --git 
a/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
new file mode 100644
index 0000000..1b13856
--- /dev/null
+++ 
b/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/util/StringBean.java
@@ -0,0 +1,20 @@
+// Copyright 2008 The Apache Software Foundation
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package org.apache.tapestry5.ioc.internal.util;
+
+public class StringBean extends BaseGenericBean<String>
+{
+
+}

Reply via email to