    001    /*
    002     * Licensed to the Apache Software Foundation (ASF) under one or more
    003     * contributor license agreements.  See the NOTICE file distributed with
    004     * this work for additional information regarding copyright ownership.
    005     * The ASF licenses this file to You under the Apache License, Version 2.0
    006     * (the "License"); you may not use this file except in compliance with
    007     * the License.  You may obtain a copy of the License at
    008     *
    009     *      http://www.apache.org/licenses/LICENSE-2.0
    010     *
    011     * Unless required by applicable law or agreed to in writing, software
    012     * distributed under the License is distributed on an "AS IS" BASIS,
    013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014     * See the License for the specific language governing permissions and
    015     * limitations under the License.
    016     */
    017    package org.apache.commons.lang3.reflect;
    018
    019    import java.lang.reflect.Array;
    020    import java.lang.reflect.GenericArrayType;
    021    import java.lang.reflect.ParameterizedType;
    022    import java.lang.reflect.Type;
    023    import java.lang.reflect.TypeVariable;
    024    import java.lang.reflect.WildcardType;
    025    import java.util.Arrays;
    026    import java.util.HashMap;
    027    import java.util.HashSet;
    028    import java.util.List;
    029    import java.util.Map;
    030    import java.util.Set;
    031
    032    import org.apache.commons.lang3.ClassUtils;
    033
    034    /**
    035     * <p> Utility methods focusing on type inspection, particularly with regard to
    036     * generics. </p>
    037     *
    038     * @since 3.0
    039     * @version $Id: TypeUtils.java 1144929 2011-07-10 18:26:16Z ggregory $
    040     */
    041    public class TypeUtils {
    042
    043        /**
    044         * <p> TypeUtils instances should NOT be constructed in standard
    045         * programming. Instead, the class should be used as
    046         * <code>TypeUtils.isAssignable(cls, toClass)</code>. </p> <p> This
    047         * constructor is public to permit tools that require a JavaBean instance to
    048         * operate. </p>
    049         */
    050        public TypeUtils() {
    051            super();
    052        }
    053
    054        /**
    055         * <p> Checks if the subject type may be implicitly cast to the target type
    056         * following the Java generics rules. If both types are {@link Class}
    057         * objects, the method returns the result of
    058         * {@link ClassUtils#isAssignable(Class, Class)}. </p>
    059         *
    060         * @param type the subject type to be assigned to the target type
    061         * @param toType the target type
    062         * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
    063         */
    064        public static boolean isAssignable(Type type, Type toType) {
    065            return isAssignable(type, toType, null);
    066        }
    067
    068        /**
    069         * <p> Checks if the subject type may be implicitly cast to the target type
    070         * following the Java generics rules. </p>
    071         *
    072         * @param type the subject type to be assigned to the target type
    073         * @param toType the target type
    074         * @param typeVarAssigns optional map of type variable assignments
    075         * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
    076         */
    077        private static boolean isAssignable(Type type, Type toType,
    078                Map<TypeVariable<?>, Type> typeVarAssigns) {
    079            if (toType == null || toType instanceof Class<?>) {
    080                return isAssignable(type, (Class<?>) toType);
    081            }
    082
    083            if (toType instanceof ParameterizedType) {
    084                return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
    085            }
    086
    087            if (toType instanceof GenericArrayType) {
    088                return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
    089            }
    090
    091            if (toType instanceof WildcardType) {
    092                return isAssignable(type, (WildcardType) toType, typeVarAssigns);
    093            }
    094
    095            // *
    096            if (toType instanceof TypeVariable<?>) {
    097                return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
    098            }
    099            // */
    100
    101            throw new IllegalStateException("found an unhandled type: " + toType);
    102        }
    103
    104        /**
    105         * <p> Checks if the subject type may be implicitly cast to the target class
    106         * following the Java generics rules. </p>
    107         *
    108         * @param type the subject type to be assigned to the target type
    109         * @param toClass the target class
    110         * @return true if <code>type</code> is assignable to <code>toClass</code>.
    111         */
    112        private static boolean isAssignable(Type type, Class<?> toClass) {
    113            if (type == null) {
    114                // consistency with ClassUtils.isAssignable() behavior
    115                return toClass == null || !toClass.isPrimitive();
    116            }
    117
    118            // only a null type can be assigned to null type which
    119            // would have cause the previous to return true
    120            if (toClass == null) {
    121                return false;
    122            }
    123
    124            // all types are assignable to themselves
    125            if (toClass.equals(type)) {
    126                return true;
    127            }
    128
    129            if (type instanceof Class<?>) {
    130                // just comparing two classes
    131                return ClassUtils.isAssignable((Class<?>) type, toClass);
    132            }
    133
    134            if (type instanceof ParameterizedType) {
    135                // only have to compare the raw type to the class
    136                return isAssignable(getRawType((ParameterizedType) type), toClass);
    137            }
    138
    139            // *
    140            if (type instanceof TypeVariable<?>) {
    141                // if any of the bounds are assignable to the class, then the
    142                // type is assignable to the class.
    143                for (Type bound : ((TypeVariable<?>) type).getBounds()) {
    144                    if (isAssignable(bound, toClass)) {
    145                        return true;
    146                    }
    147                }
    148
    149                return false;
    150            }
    151
    152            // the only classes to which a generic array type can be assigned
    153            // are class Object and array classes
    154            if (type instanceof GenericArrayType) {
    155                return toClass.equals(Object.class)
    156                        || toClass.isArray()
    157                        && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
    158                                .getComponentType());
    159            }
    160
    161            // wildcard types are not assignable to a class (though one would think
    162            // "? super Object" would be assignable to Object)
    163            if (type instanceof WildcardType) {
    164                return false;
    165            }
    166
    167            throw new IllegalStateException("found an unhandled type: " + type);
    168        }
    169
    170        /**
    171         * <p> Checks if the subject type may be implicitly cast to the target
    172         * parameterized type following the Java generics rules. </p>
    173         *
    174         * @param type the subject type to be assigned to the target type
    175         * @param toParameterizedType the target parameterized type
    176         * @param typeVarAssigns a map with type variables
    177         * @return true if <code>type</code> is assignable to <code>toType</code>.
    178         */
    179        private static boolean isAssignable(Type type, ParameterizedType toParameterizedType,
    180                Map<TypeVariable<?>, Type> typeVarAssigns) {
    181            if (type == null) {
    182                return true;
    183            }
    184
    185            // only a null type can be assigned to null type which
    186            // would have cause the previous to return true
    187            if (toParameterizedType == null) {
    188                return false;
    189            }
    190
    191            // all types are assignable to themselves
    192            if (toParameterizedType.equals(type)) {
    193                return true;
    194            }
    195
    196            // get the target type's raw type
    197            Class<?> toClass = getRawType(toParameterizedType);
    198            // get the subject type's type arguments including owner type arguments
    199            // and supertype arguments up to and including the target class.
    200            Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
    201
    202            // null means the two types are not compatible
    203            if (fromTypeVarAssigns == null) {
    204                return false;
    205            }
    206
    207            // compatible types, but there's no type arguments. this is equivalent
    208            // to comparing Map< ?, ? > to Map, and raw types are always assignable
    209            // to parameterized types.
    210            if (fromTypeVarAssigns.isEmpty()) {
    211                return true;
    212            }
    213
    214            // get the target type's type arguments including owner type arguments
    215            Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
    216                    toClass, typeVarAssigns);
    217
    218            // now to check each type argument
    219            for (Map.Entry<TypeVariable<?>, Type> entry : toTypeVarAssigns.entrySet()) {
    220                Type toTypeArg = entry.getValue();
    221                Type fromTypeArg = fromTypeVarAssigns.get(entry.getKey());
    222
    223                // parameters must either be absent from the subject type, within
    224                // the bounds of the wildcard type, or be an exact match to the
    225                // parameters of the target type.
    226                if (fromTypeArg != null
    227                        && !toTypeArg.equals(fromTypeArg)
    228                        && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
    229                                typeVarAssigns))) {
    230                    return false;
    231                }
    232            }
    233
    234            return true;
    235        }
    236
    237        /**
    238         * <p> Checks if the subject type may be implicitly cast to the target
    239         * generic array type following the Java generics rules. </p>
    240         *
    241         * @param type the subject type to be assigned to the target type
    242         * @param toGenericArrayType the target generic array type
    243         * @param typeVarAssigns a map with type variables
    244         * @return true if <code>type</code> is assignable to
    245         * <code>toGenericArrayType</code>.
    246         */
    247        private static boolean isAssignable(Type type, GenericArrayType toGenericArrayType,
    248                Map<TypeVariable<?>, Type> typeVarAssigns) {
    249            if (type == null) {
    250                return true;
    251            }
    252
    253            // only a null type can be assigned to null type which
    254            // would have cause the previous to return true
    255            if (toGenericArrayType == null) {
    256                return false;
    257            }
    258
    259            // all types are assignable to themselves
    260            if (toGenericArrayType.equals(type)) {
    261                return true;
    262            }
    263
    264            Type toComponentType = toGenericArrayType.getGenericComponentType();
    265
    266            if (type instanceof Class<?>) {
    267                Class<?> cls = (Class<?>) type;
    268
    269                // compare the component types
    270                return cls.isArray()
    271                        && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
    272            }
    273
    274            if (type instanceof GenericArrayType) {
    275                // compare the component types
    276                return isAssignable(((GenericArrayType) type).getGenericComponentType(),
    277                        toComponentType, typeVarAssigns);
    278            }
    279
    280            if (type instanceof WildcardType) {
    281                // so long as one of the upper bounds is assignable, it's good
    282                for (Type bound : getImplicitUpperBounds((WildcardType) type)) {
    283                    if (isAssignable(bound, toGenericArrayType)) {
    284                        return true;
    285                    }
    286                }
    287
    288                return false;
    289            }
    290
    291            if (type instanceof TypeVariable<?>) {
    292                // probably should remove the following logic and just return false.
    293                // type variables cannot specify arrays as bounds.
    294                for (Type bound : getImplicitBounds((TypeVariable<?>) type)) {
    295                    if (isAssignable(bound, toGenericArrayType)) {
    296                        return true;
    297                    }
    298                }
    299
    300                return false;
    301            }
    302
    303            if (type instanceof ParameterizedType) {
    304                // the raw type of a parameterized type is never an array or
    305                // generic array, otherwise the declaration would look like this:
    306                // Collection[]< ? extends String > collection;
    307                return false;
    308            }
    309
    310            throw new IllegalStateException("found an unhandled type: " + type);
    311        }
    312
    313        /**
    314         * <p> Checks if the subject type may be implicitly cast to the target
    315         * wildcard type following the Java generics rules. </p>
    316         *
    317         * @param type the subject type to be assigned to the target type
    318         * @param toWildcardType the target wildcard type
    319         * @param typeVarAssigns a map with type variables
    320         * @return true if <code>type</code> is assignable to
    321         * <code>toWildcardType</code>.
    322         */
    323        private static boolean isAssignable(Type type, WildcardType toWildcardType,
    324                Map<TypeVariable<?>, Type> typeVarAssigns) {
    325            if (type == null) {
    326                return true;
    327            }
    328
    329            // only a null type can be assigned to null type which
    330            // would have cause the previous to return true
    331            if (toWildcardType == null) {
    332                return false;
    333            }
    334
    335            // all types are assignable to themselves
    336            if (toWildcardType.equals(type)) {
    337                return true;
    338            }
    339
    340            Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
    341            Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
    342
    343            if (type instanceof WildcardType) {
    344                WildcardType wildcardType = (WildcardType) type;
    345                Type[] upperBounds = getImplicitUpperBounds(wildcardType);
    346                Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
    347
    348                for (Type toBound : toUpperBounds) {
    349                    // if there are assignments for unresolved type variables,
    350                    // now's the time to substitute them.
    351                    toBound = substituteTypeVariables(toBound, typeVarAssigns);
    352
    353                    // each upper bound of the subject type has to be assignable to
    354                    // each
    355                    // upper bound of the target type
    356                    for (Type bound : upperBounds) {
    357                        if (!isAssignable(bound, toBound, typeVarAssigns)) {
    358                            return false;
    359                        }
    360                    }
    361                }
    362
    363                for (Type toBound : toLowerBounds) {
    364                    // if there are assignments for unresolved type variables,
    365                    // now's the time to substitute them.
    366                    toBound = substituteTypeVariables(toBound, typeVarAssigns);
    367
    368                    // each lower bound of the target type has to be assignable to
    369                    // each
    370                    // lower bound of the subject type
    371                    for (Type bound : lowerBounds) {
    372                        if (!isAssignable(toBound, bound, typeVarAssigns)) {
    373                            return false;
    374                        }
    375                    }
    376                }
    377
    378                return true;
    379            }
    380
    381            for (Type toBound : toUpperBounds) {
    382                // if there are assignments for unresolved type variables,
    383                // now's the time to substitute them.
    384                if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
    385                        typeVarAssigns)) {
    386                    return false;
    387                }
    388            }
    389
    390            for (Type toBound : toLowerBounds) {
    391                // if there are assignments for unresolved type variables,
    392                // now's the time to substitute them.
    393                if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
    394                        typeVarAssigns)) {
    395                    return false;
    396                }
    397            }
    398
    399            return true;
    400        }
    401
    402        /**
    403         * <p> Checks if the subject type may be implicitly cast to the target type
    404         * variable following the Java generics rules. </p>
    405         *
    406         * @param type the subject type to be assigned to the target type
    407         * @param toTypeVariable the target type variable
    408         * @param typeVarAssigns a map with type variables
    409         * @return true if <code>type</code> is assignable to
    410         * <code>toTypeVariable</code>.
    411         */
    412        private static boolean isAssignable(Type type, TypeVariable<?> toTypeVariable,
    413                Map<TypeVariable<?>, Type> typeVarAssigns) {
    414            if (type == null) {
    415                return true;
    416            }
    417
    418            // only a null type can be assigned to null type which
    419            // would have cause the previous to return true
    420            if (toTypeVariable == null) {
    421                return false;
    422            }
    423
    424            // all types are assignable to themselves
    425            if (toTypeVariable.equals(type)) {
    426                return true;
    427            }
    428
    429            if (type instanceof TypeVariable<?>) {
    430                // a type variable is assignable to another type variable, if
    431                // and only if the former is the latter, extends the latter, or
    432                // is otherwise a descendant of the latter.
    433                Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
    434
    435                for (Type bound : bounds) {
    436                    if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
    437                        return true;
    438                    }
    439                }
    440            }
    441
    442            if (type instanceof Class<?> || type instanceof ParameterizedType
    443                    || type instanceof GenericArrayType || type instanceof WildcardType) {
    444                return false;
    445            }
    446
    447            throw new IllegalStateException("found an unhandled type: " + type);
    448        }
    449
    450        /**
    451         * <p> </p>
    452         *
    453         * @param type the type to be replaced
    454         * @param typeVarAssigns the map with type variables
    455         * @return the replaced type
    456         * @throws IllegalArgumentException if the type cannot be substituted
    457         */
    458        private static Type substituteTypeVariables(Type type, Map<TypeVariable<?>, Type> typeVarAssigns) {
    459            if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
    460                Type replacementType = typeVarAssigns.get(type);
    461
    462                if (replacementType == null) {
    463                    throw new IllegalArgumentException("missing assignment type for type variable "
    464                            + type);
    465                }
    466
    467                return replacementType;
    468            }
    469
    470            return type;
    471        }
    472
    473        /**
    474         * <p> Retrieves all the type arguments for this parameterized type
    475         * including owner hierarchy arguments such as <code>
    476         * Outer<K,V>.Inner<T>.DeepInner<E></code> . The arguments are returned in a
    477         * {@link Map} specifying the argument type for each {@link TypeVariable}.
    478         * </p>
    479         *
    480         * @param type specifies the subject parameterized type from which to
    481         * harvest the parameters.
    482         * @return a map of the type arguments to their respective type variables.
    483         */
    484        public static Map<TypeVariable<?>, Type> getTypeArguments(ParameterizedType type) {
    485            return getTypeArguments(type, getRawType(type), null);
    486        }
    487
    488        /**
    489         * <p> Gets the type arguments of a class/interface based on a subtype. For
    490         * instance, this method will determine that both of the parameters for the
    491         * interface {@link Map} are {@link Object} for the subtype
    492         * {@link java.util.Properties Properties} even though the subtype does not
    493         * directly implement the <code>Map</code> interface. <p> </p> This method
    494         * returns <code>null</code> if <code>type</code> is not assignable to
    495         * <code>toClass</code>. It returns an empty map if none of the classes or
    496         * interfaces in its inheritance hierarchy specify any type arguments. </p>
    497         * <p> A side-effect of this method is that it also retrieves the type
    498         * arguments for the classes and interfaces that are part of the hierarchy
    499         * between <code>type</code> and <code>toClass</code>. So with the above
    500         * example, this method will also determine that the type arguments for
    501         * {@link java.util.Hashtable Hashtable} are also both <code>Object</code>.
    502         * In cases where the interface specified by <code>toClass</code> is
    503         * (indirectly) implemented more than once (e.g. where <code>toClass</code>
    504         * specifies the interface {@link java.lang.Iterable Iterable} and
    505         * <code>type</code> specifies a parameterized type that implements both
    506         * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
    507         * this method will look at the inheritance hierarchy of only one of the
    508         * implementations/subclasses; the first interface encountered that isn't a
    509         * subinterface to one of the others in the <code>type</code> to
    510         * <code>toClass</code> hierarchy. </p>
    511         *
    512         * @param type the type from which to determine the type parameters of
    513         * <code>toClass</code>
    514         * @param toClass the class whose type parameters are to be determined based
    515         * on the subtype <code>type</code>
    516         * @return a map of the type assignments for the type variables in each type
    517         * in the inheritance hierarchy from <code>type</code> to
    518         * <code>toClass</code> inclusive.
    519         */
    520        public static Map<TypeVariable<?>, Type> getTypeArguments(Type type, Class<?> toClass) {
    521            return getTypeArguments(type, toClass, null);
    522        }
    523
    524        /**
    525         * <p> Return a map of the type arguments of <code>type</code> in the context of <code>toClass</code>. </p>
    526         *
    527         * @param type the type in question
    528         * @param toClass the class
    529         * @param subtypeVarAssigns a map with type variables
    530         * @return the map with type arguments
    531         */
    532        private static Map<TypeVariable<?>, Type> getTypeArguments(Type type, Class<?> toClass,
    533                Map<TypeVariable<?>, Type> subtypeVarAssigns) {
    534            if (type instanceof Class<?>) {
    535                return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
    536            }
    537
    538            if (type instanceof ParameterizedType) {
    539                return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
    540            }
    541
    542            if (type instanceof GenericArrayType) {
    543                return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
    544                        .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
    545            }
    546
    547            // since wildcard types are not assignable to classes, should this just
    548            // return null?
    549            if (type instanceof WildcardType) {
    550                for (Type bound : getImplicitUpperBounds((WildcardType) type)) {
    551                    // find the first bound that is assignable to the target class
    552                    if (isAssignable(bound, toClass)) {
    553                        return getTypeArguments(bound, toClass, subtypeVarAssigns);
    554                    }
    555                }
    556
    557                return null;
    558            }
    559
    560            // *
    561            if (type instanceof TypeVariable<?>) {
    562                for (Type bound : getImplicitBounds((TypeVariable<?>) type)) {
    563                    // find the first bound that is assignable to the target class
    564                    if (isAssignable(bound, toClass)) {
    565                        return getTypeArguments(bound, toClass, subtypeVarAssigns);
    566                    }
    567                }
    568
    569                return null;
    570            }
    571            // */
    572
    573            throw new IllegalStateException("found an unhandled type: " + type);
    574        }
    575
    576        /**
    577         * <p> Return a map of the type arguments of a parameterized type in the context of <code>toClass</code>. </p>
    578         *
    579         * @param parameterizedType the parameterized type
    580         * @param toClass the class
    581         * @param subtypeVarAssigns a map with type variables
    582         * @return the map with type arguments
    583         */
    584        private static Map<TypeVariable<?>, Type> getTypeArguments(
    585                ParameterizedType parameterizedType, Class<?> toClass,
    586                Map<TypeVariable<?>, Type> subtypeVarAssigns) {
    587            Class<?> cls = getRawType(parameterizedType);
    588
    589            // make sure they're assignable
    590            if (!isAssignable(cls, toClass)) {
    591                return null;
    592            }
    593
    594            Type ownerType = parameterizedType.getOwnerType();
    595            Map<TypeVariable<?>, Type> typeVarAssigns;
    596
    597            if (ownerType instanceof ParameterizedType) {
    598                // get the owner type arguments first
    599                ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
    600                typeVarAssigns = getTypeArguments(parameterizedOwnerType,
    601                        getRawType(parameterizedOwnerType), subtypeVarAssigns);
    602            } else {
    603                // no owner, prep the type variable assignments map
    604                typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
    605                        : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
    606            }
    607
    608            // get the subject parameterized type's arguments
    609            Type[] typeArgs = parameterizedType.getActualTypeArguments();
    610            // and get the corresponding type variables from the raw class
    611            TypeVariable<?>[] typeParams = cls.getTypeParameters();
    612
    613            // map the arguments to their respective type variables
    614            for (int i = 0; i < typeParams.length; i++) {
    615                Type typeArg = typeArgs[i];
    616                typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
    617                        .get(typeArg) : typeArg);
    618            }
    619
    620            if (toClass.equals(cls)) {
    621                // target class has been reached. Done.
    622                return typeVarAssigns;
    623            }
    624
    625            // walk the inheritance hierarchy until the target class is reached
    626            return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
    627        }
    628
    629        /**
    630         * <p> Return a map of the type arguments of a class in the context of <code>toClass</code>. </p>
    631         *
    632         * @param cls the class in question
    633         * @param toClass the context class
    634         * @param subtypeVarAssigns a map with type variables
    635         * @return the map with type arguments
    636         */
    637        private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, Class<?> toClass,
    638                Map<TypeVariable<?>, Type> subtypeVarAssigns) {
    639            // make sure they're assignable
    640            if (!isAssignable(cls, toClass)) {
    641                return null;
    642            }
    643
    644            // can't work with primitives
    645            if (cls.isPrimitive()) {
    646                // both classes are primitives?
    647                if (toClass.isPrimitive()) {
    648                    // dealing with widening here. No type arguments to be
    649                    // harvested with these two types.
    650                    return new HashMap<TypeVariable<?>, Type>();
    651                }
    652
    653                // work with wrapper the wrapper class instead of the primitive
    654                cls = ClassUtils.primitiveToWrapper(cls);
    655            }
    656
    657            // create a copy of the incoming map, or an empty one if it's null
    658            HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
    659                    : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
    660
    661            // no arguments for the parameters, or target class has been reached
    662            if (cls.getTypeParameters().length > 0 || toClass.equals(cls)) {
    663                return typeVarAssigns;
    664            }
    665
    666            // walk the inheritance hierarchy until the target class is reached
    667            return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
    668        }
    669
    670        /**
    671         * <p> Tries to determine the type arguments of a class/interface based on a
    672         * super parameterized type's type arguments. This method is the inverse of
    673         * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
    674         * type arguments based on a subtype. It is far more limited in determining
    675         * the type arguments for the subject class's type variables in that it can
    676         * only determine those parameters that map from the subject {@link Class}
    677         * object to the supertype. </p> <p> Example: {@link java.util.TreeSet
    678         * TreeSet} sets its parameter as the parameter for
    679         * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
    680         * parameter of {@link java.util.SortedSet}, which in turn sets the
    681         * parameter of {@link Set}, which in turn sets the parameter of
    682         * {@link java.util.Collection}, which in turn sets the parameter of
    683         * {@link java.lang.Iterable}. Since <code>TreeSet</code>'s parameter maps
    684         * (indirectly) to <code>Iterable</code>'s parameter, it will be able to
    685         * determine that based on the super type <code>Iterable<? extends
    686         * Map<Integer,? extends Collection<?>>></code>, the parameter of
    687         * <code>TreeSet</code> is <code>? extends Map<Integer,? extends
    688         * Collection<?>></code>. </p>
    689         *
    690         * @param cls the class whose type parameters are to be determined
    691         * @param superType the super type from which <code>cls</code>'s type
    692         * arguments are to be determined
    693         * @return a map of the type assignments that could be determined for the
    694         * type variables in each type in the inheritance hierarchy from
    695         * <code>type</code> to <code>toClass</code> inclusive.
    696         */
    697        public static Map<TypeVariable<?>, Type> determineTypeArguments(Class<?> cls,
    698                ParameterizedType superType) {
    699            Class<?> superClass = getRawType(superType);
    700
    701            // compatibility check
    702            if (!isAssignable(cls, superClass)) {
    703                return null;
    704            }
    705
    706            if (cls.equals(superClass)) {
    707                return getTypeArguments(superType, superClass, null);
    708            }
    709
    710            // get the next class in the inheritance hierarchy
    711            Type midType = getClosestParentType(cls, superClass);
    712
    713            // can only be a class or a parameterized type
    714            if (midType instanceof Class<?>) {
    715                return determineTypeArguments((Class<?>) midType, superType);
    716            }
    717
    718            ParameterizedType midParameterizedType = (ParameterizedType) midType;
    719            Class<?> midClass = getRawType(midParameterizedType);
    720            // get the type variables of the mid class that map to the type
    721            // arguments of the super class
    722            Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
    723            // map the arguments of the mid type to the class type variables
    724            mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
    725
    726            return typeVarAssigns;
    727        }
    728
    729        /**
    730         * <p>Performs a mapping of type variables.</p>
    731         *
    732         * @param <T> the generic type of the class in question
    733         * @param cls the class in question
    734         * @param parameterizedType the parameterized type
    735         * @param typeVarAssigns the map to be filled
    736         */
    737        private static <T> void mapTypeVariablesToArguments(Class<T> cls,
    738                ParameterizedType parameterizedType, Map<TypeVariable<?>, Type> typeVarAssigns) {
    739            // capture the type variables from the owner type that have assignments
    740            Type ownerType = parameterizedType.getOwnerType();
    741
    742            if (ownerType instanceof ParameterizedType) {
    743                // recursion to make sure the owner's owner type gets processed
    744                mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
    745            }
    746
    747            // parameterizedType is a generic interface/class (or it's in the owner
    748            // hierarchy of said interface/class) implemented/extended by the class
    749            // cls. Find out which type variables of cls are type arguments of
    750            // parameterizedType:
    751            Type[] typeArgs = parameterizedType.getActualTypeArguments();
    752
    753            // of the cls's type variables that are arguments of parameterizedType,
    754            // find out which ones can be determined from the super type's arguments
    755            TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
    756
    757            // use List view of type parameters of cls so the contains() method can be used:
    758            List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
    759                    .getTypeParameters());
    760
    761            for (int i = 0; i < typeArgs.length; i++) {
    762                TypeVariable<?> typeVar = typeVars[i];
    763                Type typeArg = typeArgs[i];
    764
    765                // argument of parameterizedType is a type variable of cls
    766                if (typeVarList.contains(typeArg)
    767                // type variable of parameterizedType has an assignment in
    768                        // the super type.
    769                        && typeVarAssigns.containsKey(typeVar)) {
    770                    // map the assignment to the cls's type variable
    771                    typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
    772                }
    773            }
    774        }
    775
    776        /**
    777         * <p> Closest parent type? Closest to what? The closest parent type to the
    778         * super class specified by <code>superClass</code>. </p>
    779         *
    780         * @param cls the class in question
    781         * @param superClass the super class
    782         * @return the closes parent type
    783         */
    784        private static Type getClosestParentType(Class<?> cls, Class<?> superClass) {
    785            // only look at the interfaces if the super class is also an interface
    786            if (superClass.isInterface()) {
    787                // get the generic interfaces of the subject class
    788                Type[] interfaceTypes = cls.getGenericInterfaces();
    789                // will hold the best generic interface match found
    790                Type genericInterface = null;
    791
    792                // find the interface closest to the super class
    793                for (Type midType : interfaceTypes) {
    794                    Class<?> midClass = null;
    795
    796                    if (midType instanceof ParameterizedType) {
    797                        midClass = getRawType((ParameterizedType) midType);
    798                    } else if (midType instanceof Class<?>) {
    799                        midClass = (Class<?>) midType;
    800                    } else {
    801                        throw new IllegalStateException("Unexpected generic"
    802                                + " interface type found: " + midType);
    803                    }
    804
    805                    // check if this interface is further up the inheritance chain
    806                    // than the previously found match
    807                    if (isAssignable(midClass, superClass)
    808                            && isAssignable(genericInterface, (Type) midClass)) {
    809                        genericInterface = midType;
    810                    }
    811                }
    812
    813                // found a match?
    814                if (genericInterface != null) {
    815                    return genericInterface;
    816                }
    817            }
    818
    819            // none of the interfaces were descendants of the target class, so the
    820            // super class has to be one, instead
    821            return cls.getGenericSuperclass();
    822        }
    823
    824        /**
    825         * <p> Checks if the given value can be assigned to the target type
    826         * following the Java generics rules. </p>
    827         *
    828         * @param value the value to be checked
    829         * @param type the target type
    830         * @return true of <code>value</code> is an instance of <code>type</code>.
    831         */
    832        public static boolean isInstance(Object value, Type type) {
    833            if (type == null) {
    834                return false;
    835            }
    836
    837            return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
    838                    : isAssignable(value.getClass(), type, null);
    839        }
    840
    841        /**
    842         * <p> This method strips out the redundant upper bound types in type
    843         * variable types and wildcard types (or it would with wildcard types if
    844         * multiple upper bounds were allowed). </p> <p> Example: with the variable
    845         * type declaration:
    846         *
    847         * <pre> &lt;K extends java.util.Collection&lt;String&gt; &amp;
    848         * java.util.List&lt;String&gt;&gt; </pre>
    849         *
    850         * since <code>List</code> is a subinterface of <code>Collection</code>,
    851         * this method will return the bounds as if the declaration had been:
    852         *
    853         * <pre> &lt;K extends java.util.List&lt;String&gt;&gt; </pre>
    854         *
    855         * </p>
    856         *
    857         * @param bounds an array of types representing the upper bounds of either
    858         * <code>WildcardType</code> or <code>TypeVariable</code>.
    859         * @return an array containing the values from <code>bounds</code> minus the
    860         * redundant types.
    861         */
    862        public static Type[] normalizeUpperBounds(Type[] bounds) {
    863            // don't bother if there's only one (or none) type
    864            if (bounds.length < 2) {
    865                return bounds;
    866            }
    867
    868            Set<Type> types = new HashSet<Type>(bounds.length);
    869
    870            for (Type type1 : bounds) {
    871                boolean subtypeFound = false;
    872
    873                for (Type type2 : bounds) {
    874                    if (type1 != type2 && isAssignable(type2, type1, null)) {
    875                        subtypeFound = true;
    876                        break;
    877                    }
    878                }
    879
    880                if (!subtypeFound) {
    881                    types.add(type1);
    882                }
    883            }
    884
    885            return types.toArray(new Type[types.size()]);
    886        }
    887
    888        /**
    889         * <p> Returns an array containing the sole type of {@link Object} if
    890         * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
    891         * returns the result of <code>TypeVariable.getBounds()</code> passed into
    892         * {@link #normalizeUpperBounds}. </p>
    893         *
    894         * @param typeVariable the subject type variable
    895         * @return a non-empty array containing the bounds of the type variable.
    896         */
    897        public static Type[] getImplicitBounds(TypeVariable<?> typeVariable) {
    898            Type[] bounds = typeVariable.getBounds();
    899
    900            return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
    901        }
    902
    903        /**
    904         * <p> Returns an array containing the sole value of {@link Object} if
    905         * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
    906         * it returns the result of <code>WildcardType.getUpperBounds()</code>
    907         * passed into {@link #normalizeUpperBounds}. </p>
    908         *
    909         * @param wildcardType the subject wildcard type
    910         * @return a non-empty array containing the upper bounds of the wildcard
    911         * type.
    912         */
    913        public static Type[] getImplicitUpperBounds(WildcardType wildcardType) {
    914            Type[] bounds = wildcardType.getUpperBounds();
    915
    916            return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
    917        }
    918
    919        /**
    920         * <p> Returns an array containing a single value of <code>null</code> if
    921         * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
    922         * it returns the result of <code>WildcardType.getLowerBounds()</code>. </p>
    923         *
    924         * @param wildcardType the subject wildcard type
    925         * @return a non-empty array containing the lower bounds of the wildcard
    926         * type.
    927         */
    928        public static Type[] getImplicitLowerBounds(WildcardType wildcardType) {
    929            Type[] bounds = wildcardType.getLowerBounds();
    930
    931            return bounds.length == 0 ? new Type[] { null } : bounds;
    932        }
    933
    934        /**
    935         * <p> Determines whether or not specified types satisfy the bounds of their
    936         * mapped type variables. When a type parameter extends another (such as
    937         * <code><T, S extends T></code>), uses another as a type parameter (such as
    938         * <code><T, S extends Comparable<T></code>), or otherwise depends on
    939         * another type variable to be specified, the dependencies must be included
    940         * in <code>typeVarAssigns</code>. </p>
    941         *
    942         * @param typeVarAssigns specifies the potential types to be assigned to the
    943         * type variables.
    944         * @return whether or not the types can be assigned to their respective type
    945         * variables.
    946         */
    947        public static boolean typesSatisfyVariables(Map<TypeVariable<?>, Type> typeVarAssigns) {
    948            // all types must be assignable to all the bounds of the their mapped
    949            // type variable.
    950            for (Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
    951                TypeVariable<?> typeVar = entry.getKey();
    952                Type type = entry.getValue();
    953
    954                for (Type bound : getImplicitBounds(typeVar)) {
    955                    if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
    956                            typeVarAssigns)) {
    957                        return false;
    958                    }
    959                }
    960            }
    961
    962            return true;
    963        }
    964
    965        /**
    966         * <p> Transforms the passed in type to a {@code Class} object. Type-checking method of convenience. </p>
    967         *
    968         * @param parameterizedType the type to be converted
    969         * @return the corresponding {@code Class} object
    970         * @throws IllegalStateException if the conversion fails
    971         */
    972        private static Class<?> getRawType(ParameterizedType parameterizedType) {
    973            Type rawType = parameterizedType.getRawType();
    974
    975            // check if raw type is a Class object
    976            // not currently necessary, but since the return type is Type instead of
    977            // Class, there's enough reason to believe that future versions of Java
    978            // may return other Type implementations. And type-safety checking is
    979            // rarely a bad idea.
    980            if (!(rawType instanceof Class<?>)) {
    981                throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
    982            }
    983
    984            return (Class<?>) rawType;
    985        }
    986
    987        /**
    988         * <p> Get the raw type of a Java type, given its context. Primarily for use
    989         * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
    990         * not know the runtime type of <code>type</code>: if you know you have a
    991         * {@link Class} instance, it is already raw; if you know you have a
    992         * {@link ParameterizedType}, its raw type is only a method call away. </p>
    993         *
    994         * @param type to resolve
    995         * @param assigningType type to be resolved against
    996         * @return the resolved <code>Class</code> object or <code>null</code> if
    997         * the type could not be resolved
    998         */
    999        public static Class<?> getRawType(Type type, Type assigningType) {
    1000            if (type instanceof Class<?>) {
    1001                // it is raw, no problem
    1002                return (Class<?>) type;
    1003            }
    1004
    1005            if (type instanceof ParameterizedType) {
    1006                // simple enough to get the raw type of a ParameterizedType
    1007                return getRawType((ParameterizedType) type);
    1008            }
    1009
    1010            if (type instanceof TypeVariable<?>) {
    1011                if (assigningType == null) {
    1012                    return null;
    1013                }
    1014
    1015                // get the entity declaring this type variable
    1016                Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
    1017
    1018                // can't get the raw type of a method- or constructor-declared type
    1019                // variable
    1020                if (!(genericDeclaration instanceof Class<?>)) {
    1021                    return null;
    1022                }
    1023
    1024                // get the type arguments for the declaring class/interface based
    1025                // on the enclosing type
    1026                Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
    1027                        (Class<?>) genericDeclaration);
    1028
    1029                // enclosingType has to be a subclass (or subinterface) of the
    1030                // declaring type
    1031                if (typeVarAssigns == null) {
    1032                    return null;
    1033                }
    1034
    1035                // get the argument assigned to this type variable
    1036                Type typeArgument = typeVarAssigns.get(type);
    1037
    1038                if (typeArgument == null) {
    1039                    return null;
    1040                }
    1041
    1042                // get the argument for this type variable
    1043                return getRawType(typeArgument, assigningType);
    1044            }
    1045
    1046            if (type instanceof GenericArrayType) {
    1047                // get raw component type
    1048                Class<?> rawComponentType = getRawType(((GenericArrayType) type)
    1049                        .getGenericComponentType(), assigningType);
    1050
    1051                // create array type from raw component type and return its class
    1052                return Array.newInstance(rawComponentType, 0).getClass();
    1053            }
    1054
    1055            // (hand-waving) this is not the method you're looking for
    1056            if (type instanceof WildcardType) {
    1057                return null;
    1058            }
    1059
    1060            throw new IllegalArgumentException("unknown type: " + type);
    1061        }
    1062
    1063        /**
    1064         * Learn whether the specified type denotes an array type.
    1065         * @param type the type to be checked
    1066         * @return <code>true</code> if <code>type</code> is an array class or a {@link GenericArrayType}.
    1067         */
    1068        public static boolean isArrayType(Type type) {
    1069            return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
    1070        }
    1071
    1072        /**
    1073         * Get the array component type of <code>type</code>.
    1074         * @param type the type to be checked
    1075         * @return component type or null if type is not an array type
    1076         */
    1077        public static Type getArrayComponentType(Type type) {
    1078            if (type instanceof Class<?>) {
    1079                Class<?> clazz = (Class<?>) type;
    1080                return clazz.isArray() ? clazz.getComponentType() : null;
    1081            }
    1082            if (type instanceof GenericArrayType) {
    1083                return ((GenericArrayType) type).getGenericComponentType();
    1084            }
    1085            return null;
    1086        }
    1087
    1088    }