    001    // Copyright 2008, 2010 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    // http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.ioc.internal.util;
    016
    017    import java.lang.reflect.*;
    018    import java.util.LinkedList;
    019
    020    /**
    021     * Static methods related to the use of JDK 1.5 generics.
    022     */
    023    @SuppressWarnings("unchecked")
    024    public class GenericsUtils
    025    {
    026        /**
    027         * Analyzes the method in the context of containingClass and returns the Class that is represented by
    028         * the method's generic return type. Any parameter information in the generic return type is lost. If you want
    029         * to preserve the type parameters of the return type consider using
    030         * {@link #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)}.
    031         *
    032         * @param containingClass class which either contains or inherited the method
    033         * @param method          method from which to extract the return type
    034         * @return the class represented by the methods generic return type, resolved based on the context .
    035         * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Method)
    036         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
    037         * @see #asClass(java.lang.reflect.Type)
    038         */
    039        public static Class<?> extractGenericReturnType(Class<?> containingClass, Method method)
    040        {
    041            return asClass(resolve(method.getGenericReturnType(), containingClass));
    042        }
    043
    044
    045        /**
    046         * Analyzes the field in the context of containingClass and returns the Class that is represented by
    047         * the field's generic type. Any parameter information in the generic type is lost, if you want
    048         * to preserve the type parameters of the return type consider using
    049         * {@link #getTypeVariableIndex(java.lang.reflect.TypeVariable)}.
    050         *
    051         * @param containingClass class which either contains or inherited the field
    052         * @param field           field from which to extract the type
    053         * @return the class represented by the field's generic type, resolved based on the containingClass.
    054         * @see #extractActualType(java.lang.reflect.Type, java.lang.reflect.Field)
    055         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
    056         * @see #asClass(java.lang.reflect.Type)
    057         */
    058        public static Class extractGenericFieldType(Class containingClass, Field field)
    059        {
    060            return asClass(resolve(field.getGenericType(), containingClass));
    061        }
    062
    063        /**
    064         * Analyzes the method in the context of containingClass and returns the Class that is represented by
    065         * the method's generic return type. Any parameter information in the generic return type is lost.
    066         *
    067         * @param containingType Type which is/represents the class that either contains or inherited the method
    068         * @param method         method from which to extract the generic return type
    069         * @return the generic type represented by the methods generic return type, resolved based on the containingType.
    070         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
    071         */
    072        public static Type extractActualType(Type containingType, Method method)
    073        {
    074            return resolve(method.getGenericReturnType(), containingType);
    075        }
    076
    077        /**
    078         * Analyzes the method in the context of containingClass and returns the Class that is represented by
    079         * the method's generic return type. Any parameter information in the generic return type is lost.
    080         *
    081         * @param containingType Type which is/represents the class that either contains or inherited the field
    082         * @param field          field from which to extract the generic return type
    083         * @return the generic type represented by the methods generic return type, resolved based on the containingType.
    084         * @see #resolve(java.lang.reflect.Type,java.lang.reflect.Type)
    085         */
    086        public static Type extractActualType(Type containingType, Field field)
    087        {
    088            return resolve(field.getGenericType(), containingType);
    089        }
    090
    091        /**
    092         * Resolves the type parameter based on the context of the containingType.
    093         * <p/>
    094         * {@link java.lang.reflect.TypeVariable} will be unwrapped to the type argument resolved form the class
    095         * hierarchy. This may be something other than a simple Class if the type argument is a ParameterizedType for
    096         * instance (e.g. List&lt;E>; List&lt;Map&lt;Long, String>>, E would be returned as a ParameterizedType with the raw
    097         * type Map and type arguments Long and String.
    098         * <p/>
    099         *
    100         * @param type
    101         *          the generic type (ParameterizedType, GenericArrayType, WildcardType, TypeVariable) to be resolved
    102         * @param containingType
    103         *          the type which his
    104         * @return
    105         *          the type resolved to the best of our ability.
    106         * @since 5.2.?
    107         */
    108        public static Type resolve(final Type type, final Type containingType)
    109        {
    110            // The type isn't generic. (String, Long, etc)
    111            if (type instanceof Class)
    112                return type;
    113
    114            // List<T>, List<String>, List<T extends Number>
    115            if (type instanceof ParameterizedType)
    116                return resolve((ParameterizedType) type, containingType);
    117
    118            // T[], List<String>[], List<T>[]
    119            if (type instanceof GenericArrayType)
    120                return resolve((GenericArrayType) type, containingType);
    121
    122            // List<? extends T>, List<? extends Object & Comparable & Serializable>
    123            if (type instanceof WildcardType)
    124                return resolve((WildcardType) type, containingType);
    125
    126            // T
    127            if (type instanceof TypeVariable)
    128                return resolve((TypeVariable) type, containingType);
    129
    130            // I'm leaning towards an exception here.
    131            return type;
    132        }
    133
    134
    135        /**
    136         * Determines if the suspected super type is assignable from the suspected sub type.
    137         *
    138         * @param suspectedSuperType
    139         *          e.g. GenericDAO&lt;Pet, String>
    140         * @param suspectedSubType
    141         *          e.g. PetDAO extends GenericDAO&lt;Pet,String>
    142         * @return
    143         *          true if (sourceType)targetClass is a valid cast
    144         */
    145        public static boolean isAssignableFrom(Type suspectedSuperType, Type suspectedSubType)
    146        {
    147            final Class suspectedSuperClass = asClass(suspectedSuperType);
    148            final Class suspectedSubClass = asClass(suspectedSubType);
    149
    150            // The raw types need to be compatible.
    151            if (!suspectedSuperClass.isAssignableFrom(suspectedSubClass))
    152            {
    153                return false;
    154            }
    155
    156            // From this point we know that the raw types are assignable.
    157            // We need to figure out what the generic parameters in the targetClass are
    158            // as they pertain to the sourceType.
    159
    160            if (suspectedSuperType instanceof WildcardType)
    161            {
    162                // ? extends Number
    163                // needs to match all the bounds (there will only be upper bounds or lower bounds
    164                for (Type t : ((WildcardType) suspectedSuperType).getUpperBounds())
    165                {
    166                    if (!isAssignableFrom(t, suspectedSubType)) return false;
    167                }
    168                for (Type t : ((WildcardType) suspectedSuperType).getLowerBounds())
    169                {
    170                    if (!isAssignableFrom(suspectedSubType, t)) return false;
    171                }
    172                return true;
    173            }
    174
    175            Type curType = suspectedSubType;
    176            Class curClass;
    177
    178            while (curType != null && !curType.equals(Object.class))
    179            {
    180                curClass = asClass(curType);
    181
    182                if (curClass.equals(suspectedSuperClass))
    183                {
    184                    final Type resolved = resolve(curType, suspectedSubType);
    185
    186                    if (suspectedSuperType instanceof Class)
    187                    {
    188                        if ( resolved instanceof Class )
    189                            return suspectedSuperType.equals(resolved);
    190
    191                        // They may represent the same class, but the suspectedSuperType is not parameterized. The parameter
    192                        // types default to Object so they must be a match.
    193                        // e.g. Pair p = new StringLongPair();
    194                        //      Pair p = new Pair<? extends Number, String>
    195
    196                        return true;
    197                    }
    198
    199                    if (suspectedSuperType instanceof ParameterizedType)
    200                    {
    201                        if (resolved instanceof ParameterizedType)
    202                        {
    203                            final Type[] type1Arguments = ((ParameterizedType) suspectedSuperType).getActualTypeArguments();
    204                            final Type[] type2Arguments = ((ParameterizedType) resolved).getActualTypeArguments();
    205                            if (type1Arguments.length != type2Arguments.length) return false;
    206
    207                            for (int i = 0; i < type1Arguments.length; ++i)
    208                            {
    209                                if (!isAssignableFrom(type1Arguments[i], type2Arguments[i])) return false;
    210                            }
    211                            return true;
    212                        }
    213                    }
    214                    else if (suspectedSuperType instanceof GenericArrayType)
    215                    {
    216                        if (resolved instanceof GenericArrayType)
    217                        {
    218                            return isAssignableFrom(
    219                                    ((GenericArrayType) suspectedSuperType).getGenericComponentType(),
    220                                    ((GenericArrayType) resolved).getGenericComponentType()
    221                            );
    222                        }
    223                    }
    224
    225                    return false;
    226                }
    227
    228                final Type[] types = curClass.getGenericInterfaces();
    229                for (Type t : types)
    230                {
    231                    final Type resolved = resolve(t, suspectedSubType);
    232                    if (isAssignableFrom(suspectedSuperType, resolved))
    233                        return true;
    234                }
    235
    236                curType = curClass.getGenericSuperclass();
    237            }
    238            return false;
    239        }
    240
    241        /**
    242         * Get the class represented by the reflected type.
    243         * This method is lossy; You cannot recover the type information from the class that is returned.
    244         * <p/>
    245         * {@code TypeVariable} the first bound is returned. If your type variable extends multiple interfaces that information
    246         * is lost.
    247         * <p/>
    248         * {@code WildcardType} the first lower bound is returned. If the wildcard is defined with upper bounds
    249         * then {@code Object} is returned.
    250         *
    251         * @param actualType
    252         *           a Class, ParameterizedType, GenericArrayType
    253         * @return the un-parameterized class associated with the type.
    254         */
    255        public static Class asClass(Type actualType)
    256        {
    257            if (actualType instanceof Class) return (Class) actualType;
    258
    259            if (actualType instanceof ParameterizedType)
    260            {
    261                final Type rawType = ((ParameterizedType) actualType).getRawType();
    262                // The sun implementation returns getRawType as Class<?>, but there is room in the interface for it to be
    263                // some other Type. We'll assume it's a Class.
    264                // TODO: consider logging or throwing our own exception for that day when "something else" causes some confusion
    265                return (Class) rawType;
    266            }
    267
    268            if (actualType instanceof GenericArrayType)
    269            {
    270                final Type type = ((GenericArrayType) actualType).getGenericComponentType();
    271                return Array.newInstance(asClass(type), 0).getClass();
    272            }
    273
    274            if (actualType instanceof TypeVariable)
    275            {
    276                // Support for List<T extends Number>
    277                // There is always at least one bound. If no bound is specified in the source then it will be Object.class
    278                return asClass(((TypeVariable) actualType).getBounds()[0]);
    279            }
    280
    281            if (actualType instanceof WildcardType)
    282            {
    283                final WildcardType wildcardType = (WildcardType) actualType;
    284                final Type[] bounds = wildcardType.getLowerBounds();
    285                if (bounds != null && bounds.length > 0)
    286                {
    287                    return asClass(bounds[0]);
    288                }
    289                // If there is no lower bounds then the only thing that makes sense is Object.
    290                return Object.class;
    291            }
    292
    293            throw new RuntimeException(String.format("Unable to convert %s to Class.", actualType));
    294        }
    295
    296        /**
    297         * Convert the type into a string. The string representation approximates the code that would be used to define the
    298         * type.
    299         *
    300         * @param type - the type.
    301         * @return a string representation of the type, similar to how it was declared.
    302         */
    303        public static String toString(Type type)
    304        {
    305            if ( type instanceof ParameterizedType ) return toString((ParameterizedType)type);
    306            if ( type instanceof WildcardType ) return toString((WildcardType)type);
    307            if ( type instanceof GenericArrayType) return toString((GenericArrayType)type);
    308            if ( type instanceof Class )
    309            {
    310                final Class theClass = (Class) type;
    311                return (theClass.isArray() ? theClass.getName() + "[]" : theClass.getName());
    312            }
    313            return type.toString();
    314        }
    315
    316        /**
    317         * Method to resolve a TypeVariable to it's most
    318         * <a href="http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#112582">reifiable</a> form.
    319         * <p/>
    320         * <p/>
    321         * How to resolve a TypeVariable:<br/>
    322         * All of the TypeVariables defined by a generic class will be given a Type by any class that extends it. The Type
    323         * given may or may not be reifiable; it may be another TypeVariable for instance.
    324         * <p/>
    325         * Consider <br/>
    326         * <i>class Pair&gt;A,B> { A getA(){...}; ...}</i><br/>
    327         * <i>class StringLongPair extends Pair&gt;String, Long> { }</i><br/>
    328         * <p/>
    329         * To resolve the actual return type of Pair.getA() you must first resolve the TypeVariable "A".
    330         * We can do that by first finding the index of "A" in the Pair.class.getTypeParameters() array of TypeVariables.
    331         * <p/>
    332         * To get to the Type provided by StringLongPair you access the generics information by calling
    333         * StringLongPair.class.getGenericSuperclass; this will be a ParameterizedType. ParameterizedType gives you access
    334         * to the actual type arguments provided to Pair by StringLongPair. The array is in the same order as the array in
    335         * Pair.class.getTypeParameters so you can use the index we discovered earlier to extract the Type; String.class.
    336         * <p/>
    337         * When extracting Types we only have to consider the superclass hierarchy and not the interfaces implemented by
    338         * the class. When a class implements a generic interface it must provide types for the interface and any generic
    339         * methods implemented from the interface will be re-defined by the class with it's generic type variables.
    340         *
    341         * @param typeVariable   - the type variable to resolve.
    342         * @param containingType - the shallowest class in the class hierarchy (furthest from Object) where typeVariable is defined.
    343         * @return a Type that has had all possible TypeVariables resolved that have been defined between the type variable
    344         *         declaration and the containingType.
    345         */
    346        private static Type resolve(TypeVariable typeVariable, Type containingType)
    347        {
    348            // The generic declaration is either a Class, Method or Constructor
    349            final GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
    350
    351            if (!(genericDeclaration instanceof Class))
    352            {
    353                // It's a method or constructor. The best we can do here is try to resolve the bounds
    354                // e.g. <T extends E> T getT(T param){} where E is defined by the class.
    355                final Type bounds0 = typeVariable.getBounds()[0];
    356                return resolve(bounds0, containingType);
    357            }
    358
    359            final Class typeVariableOwner = (Class) genericDeclaration;
    360
    361            // find the typeOwner in the containingType's hierarchy
    362            final LinkedList<Type> stack = new LinkedList<Type>();
    363
    364            // If you pass a List<Long> as the containingType then the TypeVariable is going to be resolved by the
    365            // containingType and not the super class.
    366            if (containingType instanceof ParameterizedType)
    367            {
    368                stack.add(containingType);
    369            }
    370
    371            Class theClass = asClass(containingType);
    372            Type genericSuperclass = theClass.getGenericSuperclass();
    373            while (genericSuperclass != null && // true for interfaces with no superclass
    374                    !theClass.equals(Object.class) &&
    375                    !theClass.equals(typeVariableOwner))
    376            {
    377                stack.addFirst(genericSuperclass);
    378                theClass = asClass(genericSuperclass);
    379                genericSuperclass = theClass.getGenericSuperclass();
    380            }
    381
    382            int i = getTypeVariableIndex(typeVariable);
    383            Type resolved = typeVariable;
    384            for (Type t : stack)
    385            {
    386                if (t instanceof ParameterizedType)
    387                {
    388                    resolved = ((ParameterizedType) t).getActualTypeArguments()[i];
    389                    if (resolved instanceof Class) return resolved;
    390                    if (resolved instanceof TypeVariable)
    391                    {
    392                        // Need to look at the next class in the hierarchy
    393                        i = getTypeVariableIndex((TypeVariable) resolved);
    394                        continue;
    395                    }
    396                    return resolve(resolved, containingType);
    397                }
    398            }
    399
    400            // the only way we get here is if resolved is still a TypeVariable, otherwise an
    401            // exception is thrown or a value is returned.
    402            return ((TypeVariable) resolved).getBounds()[0];
    403        }
    404
    405        /**
    406         * @param type           - something like List&lt;T>[] or List&lt;? extends T>[] or T[]
    407         * @param containingType - the shallowest type in the hierarchy where type is defined.
    408         * @return either the passed type if no changes required or a copy with a best effort resolve of the component type.
    409         */
    410        private static GenericArrayType resolve(GenericArrayType type, Type containingType)
    411        {
    412            final Type componentType = type.getGenericComponentType();
    413
    414            if (!(componentType instanceof Class))
    415            {
    416                final Type resolved = resolve(componentType, containingType);
    417                return create(resolved);
    418            }
    419
    420            return type;
    421        }
    422
    423        /**
    424         * @param type           - something like List&lt;T>, List&lt;T extends Number>
    425         * @param containingType - the shallowest type in the hierarchy where type is defined.
    426         * @return the passed type if nothing to resolve or a copy of the type with the type arguments resolved.
    427         */
    428        private static ParameterizedType resolve(ParameterizedType type, Type containingType)
    429        {
    430            // Use a copy because we're going to modify it.
    431            final Type[] types = type.getActualTypeArguments().clone();
    432
    433            boolean modified = resolve(types, containingType);
    434            return modified ? create(type.getRawType(), type.getOwnerType(), types) : type;
    435        }
    436
    437        /**
    438         * @param type           - something like List&lt;? super T>, List<&lt;? extends T>, List&lt;? extends T & Comparable&lt? super T>>
    439         * @param containingType - the shallowest type in the hierarchy where type is defined.
    440         * @return the passed type if nothing to resolve or a copy of the type with the upper and lower bounds resolved.
    441         */
    442        private static WildcardType resolve(WildcardType type, Type containingType)
    443        {
    444            // Use a copy because we're going to modify them.
    445            final Type[] upper = type.getUpperBounds().clone();
    446            final Type[] lower = type.getLowerBounds().clone();
    447
    448            boolean modified = resolve(upper, containingType);
    449            modified = modified || resolve(lower, containingType);
    450
    451            return modified ? create(upper, lower) : type;
    452        }
    453
    454        /**
    455         * @param types          - Array of types to resolve. The unresolved type is replaced in the array with the resolved type.
    456         * @param containingType - the shallowest type in the hierarchy where type is defined.
    457         * @return true if any of the types were resolved.
    458         */
    459        private static boolean resolve(Type[] types, Type containingType)
    460        {
    461            boolean modified = false;
    462            for (int i = 0; i < types.length; ++i)
    463            {
    464                Type t = types[i];
    465                if (!(t instanceof Class))
    466                {
    467                    modified = true;
    468                    final Type resolved = resolve(t, containingType);
    469                    if (!resolved.equals(t))
    470                    {
    471                        types[i] = resolved;
    472                        modified = true;
    473                    }
    474                }
    475            }
    476            return modified;
    477        }
    478
    479        /**
    480         * @param rawType       - the un-parameterized type.
    481         * @param ownerType     - the outer class or null if the class is not defined within another class.
    482         * @param typeArguments - type arguments.
    483         * @return a copy of the type with the typeArguments replaced.
    484         */
    485        static ParameterizedType create(final Type rawType, final Type ownerType, final Type[] typeArguments)
    486        {
    487            return new ParameterizedType()
    488            {
    489                public Type[] getActualTypeArguments()
    490                {
    491                    return typeArguments;
    492                }
    493
    494                public Type getRawType()
    495                {
    496                    return rawType;
    497                }
    498
    499                public Type getOwnerType()
    500                {
    501                    return ownerType;
    502                }
    503
    504                @Override
    505                public String toString()
    506                {
    507                    return GenericsUtils.toString(this);
    508                }
    509            };
    510        }
    511
    512        static GenericArrayType create(final Type componentType)
    513        {
    514            return new GenericArrayType()
    515            {
    516                public Type getGenericComponentType()
    517                {
    518                    return componentType;
    519                }
    520
    521                @Override
    522                public String toString()
    523                {
    524                    return GenericsUtils.toString(this);
    525                }
    526            };
    527        }
    528
    529        /**
    530         * @param upperBounds - e.g. ? extends Number
    531         * @param lowerBounds - e.g. ? super Long
    532         * @return An new copy of the type with the upper and lower bounds replaced.
    533         */
    534        static WildcardType create(final Type[] upperBounds, final Type[] lowerBounds)
    535        {
    536
    537            return new WildcardType()
    538            {
    539                public Type[] getUpperBounds()
    540                {
    541                    return upperBounds;
    542                }
    543
    544                public Type[] getLowerBounds()
    545                {
    546                    return lowerBounds;
    547                }
    548
    549                @Override
    550                public String toString()
    551                {
    552                    return GenericsUtils.toString(this);
    553                }
    554            };
    555        }
    556
    557        static String toString(ParameterizedType pt)
    558        {
    559            String s = toString(pt.getActualTypeArguments());
    560            return String.format("%s<%s>", toString(pt.getRawType()), s);
    561        }
    562
    563        static String toString(GenericArrayType gat)
    564        {
    565            return String.format("%s[]", toString(gat.getGenericComponentType()));
    566        }
    567
    568        static String toString(WildcardType wt)
    569        {
    570            final boolean isSuper = wt.getLowerBounds().length > 0;
    571            return String.format("? %s %s",
    572                    isSuper ? "super" : "extends",
    573                    isSuper ? toString(wt.getLowerBounds()) : toString(wt.getLowerBounds()));
    574        }
    575
    576        static String toString(Type[] types)
    577        {
    578            StringBuilder sb = new StringBuilder();
    579            for ( Type t : types )
    580            {
    581                sb.append(toString(t)).append(", ");
    582            }
    583            return sb.substring(0, sb.length() - 2);// drop last ,
    584        }
    585
    586        /**
    587         * Find the index of the TypeVariable in the classes parameters. The offset can be used on a subclass to find
    588         * the actual type.
    589         *
    590         * @param typeVariable - the type variable in question.
    591         * @return the index of the type variable in it's declaring class/method/constructor's type parameters.
    592         */
    593        private static int getTypeVariableIndex(final TypeVariable typeVariable)
    594        {
    595            // the label from the class (the T in List<T>, the K or V in Map<K,V>, etc)
    596            final String typeVarName = typeVariable.getName();
    597            final TypeVariable[] typeParameters = typeVariable.getGenericDeclaration().getTypeParameters();
    598            for (int typeArgumentIndex = 0; typeArgumentIndex < typeParameters.length; typeArgumentIndex++)
    599            {
    600                // The .equals for TypeVariable may not be compatible, a name check should be sufficient.
    601                if (typeParameters[typeArgumentIndex].getName().equals(typeVarName))
    602                    return typeArgumentIndex;
    603            }
    604
    605            // The only way this could happen is if the TypeVariable is hand built incorrectly, or it's corrupted.
    606            throw new RuntimeException(
    607                    String.format("%s does not have a TypeVariable matching %s", typeVariable.getGenericDeclaration(), typeVariable));
    608        }
    609    }