    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 */
    017package org.apache.commons.lang3.reflect;
    018
    019import java.lang.reflect.Array;
    020import java.lang.reflect.GenericArrayType;
    021import java.lang.reflect.GenericDeclaration;
    022import java.lang.reflect.ParameterizedType;
    023import java.lang.reflect.Type;
    024import java.lang.reflect.TypeVariable;
    025import java.lang.reflect.WildcardType;
    026import java.util.Arrays;
    027import java.util.Collections;
    028import java.util.HashMap;
    029import java.util.HashSet;
    030import java.util.List;
    031import java.util.Map;
    032import java.util.Objects;
    033import java.util.Set;
    034
    035import org.apache.commons.lang3.ArrayUtils;
    036import org.apache.commons.lang3.ClassUtils;
    037import org.apache.commons.lang3.ObjectUtils;
    038import org.apache.commons.lang3.Validate;
    039import org.apache.commons.lang3.builder.Builder;
    040
    041/**
    042 * Utility methods focusing on type inspection, particularly with regard to
    043 * generics.
    044 *
    045 * @since 3.0
    046 */
    047public class TypeUtils {
    048
    049    /**
    050     * GenericArrayType implementation class.
    051     * @since 3.2
    052     */
    053    private static final class GenericArrayTypeImpl implements GenericArrayType {
    054        private final Type componentType;
    055
    056        /**
    057         * Constructor
    058         * @param componentType of this array type
    059         */
    060        private GenericArrayTypeImpl(final Type componentType) {
    061            this.componentType = componentType;
    062        }
    063
    064        /**
    065         * {@inheritDoc}
    066         */
    067        @Override
    068        public boolean equals(final Object obj) {
    069            return obj == this || obj instanceof GenericArrayType && TypeUtils.equals(this, (GenericArrayType) obj);
    070        }
    071
    072        /**
    073         * {@inheritDoc}
    074         */
    075        @Override
    076        public Type getGenericComponentType() {
    077            return componentType;
    078        }
    079
    080        /**
    081         * {@inheritDoc}
    082         */
    083        @Override
    084        public int hashCode() {
    085            int result = 67 << 4;
    086            result |= componentType.hashCode();
    087            return result;
    088        }
    089
    090        /**
    091         * {@inheritDoc}
    092         */
    093        @Override
    094        public String toString() {
    095            return TypeUtils.toString(this);
    096        }
    097    }
    098
    099    /**
    100     * ParameterizedType implementation class.
    101     * @since 3.2
    102     */
    103    private static final class ParameterizedTypeImpl implements ParameterizedType {
    104        private final Class<?> raw;
    105        private final Type useOwner;
    106        private final Type[] typeArguments;
    107
    108        /**
    109         * Constructor
    110         * @param rawClass type
    111         * @param useOwner owner type to use, if any
    112         * @param typeArguments formal type arguments
    113         */
    114        private ParameterizedTypeImpl(final Class<?> rawClass, final Type useOwner, final Type[] typeArguments) {
    115            this.raw = rawClass;
    116            this.useOwner = useOwner;
    117            this.typeArguments = Arrays.copyOf(typeArguments, typeArguments.length, Type[].class);
    118        }
    119
    120        /**
    121         * {@inheritDoc}
    122         */
    123        @Override
    124        public boolean equals(final Object obj) {
    125            return obj == this || obj instanceof ParameterizedType && TypeUtils.equals(this, ((ParameterizedType) obj));
    126        }
    127
    128        /**
    129         * {@inheritDoc}
    130         */
    131        @Override
    132        public Type[] getActualTypeArguments() {
    133            return typeArguments.clone();
    134        }
    135
    136        /**
    137         * {@inheritDoc}
    138         */
    139        @Override
    140        public Type getOwnerType() {
    141            return useOwner;
    142        }
    143
    144        /**
    145         * {@inheritDoc}
    146         */
    147        @Override
    148        public Type getRawType() {
    149            return raw;
    150        }
    151
    152        /**
    153         * {@inheritDoc}
    154         */
    155        @Override
    156        public int hashCode() {
    157            int result = 71 << 4;
    158            result |= raw.hashCode();
    159            result <<= 4;
    160            result |= Objects.hashCode(useOwner);
    161            result <<= 8;
    162            result |= Arrays.hashCode(typeArguments);
    163            return result;
    164        }
    165
    166        /**
    167         * {@inheritDoc}
    168         */
    169        @Override
    170        public String toString() {
    171            return TypeUtils.toString(this);
    172        }
    173    }
    174
    175    /**
    176     * {@link WildcardType} builder.
    177     * @since 3.2
    178     */
    179    public static class WildcardTypeBuilder implements Builder<WildcardType> {
    180        private Type[] upperBounds;
    181
    182        private Type[] lowerBounds;
    183        /**
    184         * Constructor
    185         */
    186        private WildcardTypeBuilder() {
    187        }
    188
    189        /**
    190         * {@inheritDoc}
    191         */
    192        @Override
    193        public WildcardType build() {
    194            return new WildcardTypeImpl(upperBounds, lowerBounds);
    195        }
    196
    197        /**
    198         * Specify lower bounds of the wildcard type to build.
    199         * @param bounds to set
    200         * @return {@code this}
    201         */
    202        public WildcardTypeBuilder withLowerBounds(final Type... bounds) {
    203            this.lowerBounds = bounds;
    204            return this;
    205        }
    206
    207        /**
    208         * Specify upper bounds of the wildcard type to build.
    209         * @param bounds to set
    210         * @return {@code this}
    211         */
    212        public WildcardTypeBuilder withUpperBounds(final Type... bounds) {
    213            this.upperBounds = bounds;
    214            return this;
    215        }
    216    }
    217
    218    /**
    219     * WildcardType implementation class.
    220     * @since 3.2
    221     */
    222    private static final class WildcardTypeImpl implements WildcardType {
    223        private final Type[] upperBounds;
    224        private final Type[] lowerBounds;
    225
    226        /**
    227         * Constructor
    228         * @param upperBounds of this type
    229         * @param lowerBounds of this type
    230         */
    231        private WildcardTypeImpl(final Type[] upperBounds, final Type[] lowerBounds) {
    232            this.upperBounds = ObjectUtils.defaultIfNull(upperBounds, ArrayUtils.EMPTY_TYPE_ARRAY);
    233            this.lowerBounds = ObjectUtils.defaultIfNull(lowerBounds, ArrayUtils.EMPTY_TYPE_ARRAY);
    234        }
    235
    236        /**
    237         * {@inheritDoc}
    238         */
    239        @Override
    240        public boolean equals(final Object obj) {
    241            return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj);
    242        }
    243
    244        /**
    245         * {@inheritDoc}
    246         */
    247        @Override
    248        public Type[] getLowerBounds() {
    249            return lowerBounds.clone();
    250        }
    251
    252        /**
    253         * {@inheritDoc}
    254         */
    255        @Override
    256        public Type[] getUpperBounds() {
    257            return upperBounds.clone();
    258        }
    259
    260        /**
    261         * {@inheritDoc}
    262         */
    263        @Override
    264        public int hashCode() {
    265            int result = 73 << 8;
    266            result |= Arrays.hashCode(upperBounds);
    267            result <<= 8;
    268            result |= Arrays.hashCode(lowerBounds);
    269            return result;
    270        }
    271
    272        /**
    273         * {@inheritDoc}
    274         */
    275        @Override
    276        public String toString() {
    277            return TypeUtils.toString(this);
    278        }
    279    }
    280
    281    /**
    282     * A wildcard instance matching {@code ?}.
    283     * @since 3.2
    284     */
    285    public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build();
    286
    287    /**
    288     * Appends {@code types} to {@code builder} with separator {@code sep}.
    289     *
    290     * @param builder destination
    291     * @param sep separator
    292     * @param types to append
    293     * @return {@code builder}
    294     * @since 3.2
    295     */
    296    private static <T> StringBuilder appendAllTo(final StringBuilder builder, final String sep,
    297        @SuppressWarnings("unchecked") final T... types) {
    298        Validate.notEmpty(Validate.noNullElements(types));
    299        if (types.length > 0) {
    300            builder.append(toString(types[0]));
    301            for (int i = 1; i < types.length; i++) {
    302                builder.append(sep).append(toString(types[i]));
    303            }
    304        }
    305        return builder;
    306    }
    307
    308    private static void appendRecursiveTypes(final StringBuilder builder, final int[] recursiveTypeIndexes,
    309        final Type[] argumentTypes) {
    310        for (int i = 0; i < recursiveTypeIndexes.length; i++) {
    311            appendAllTo(builder.append('<'), ", ", argumentTypes[i].toString()).append('>');
    312        }
    313
    314        final Type[] argumentsFiltered = ArrayUtils.removeAll(argumentTypes, recursiveTypeIndexes);
    315
    316        if (argumentsFiltered.length > 0) {
    317            appendAllTo(builder.append('<'), ", ", argumentsFiltered).append('>');
    318        }
    319    }
    320
    321    /**
    322     * Formats a {@link Class} as a {@link String}.
    323     *
    324     * @param cls {@code Class} to format
    325     * @return String
    326     * @since 3.2
    327     */
    328    private static String classToString(final Class<?> cls) {
    329        if (cls.isArray()) {
    330            return toString(cls.getComponentType()) + "[]";
    331        }
    332
    333        final StringBuilder buf = new StringBuilder();
    334
    335        if (cls.getEnclosingClass() != null) {
    336            buf.append(classToString(cls.getEnclosingClass())).append('.').append(cls.getSimpleName());
    337        } else {
    338            buf.append(cls.getName());
    339        }
    340        if (cls.getTypeParameters().length > 0) {
    341            buf.append('<');
    342            appendAllTo(buf, ", ", cls.getTypeParameters());
    343            buf.append('>');
    344        }
    345        return buf.toString();
    346    }
    347
    348    /**
    349     * Tests, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
    350     *
    351     * @param type the type to check for type variables
    352     * @return boolean
    353     * @since 3.2
    354     */
    355    public static boolean containsTypeVariables(final Type type) {
    356        if (type instanceof TypeVariable<?>) {
    357            return true;
    358        }
    359        if (type instanceof Class<?>) {
    360            return ((Class<?>) type).getTypeParameters().length > 0;
    361        }
    362        if (type instanceof ParameterizedType) {
    363            for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
    364                if (containsTypeVariables(arg)) {
    365                    return true;
    366                }
    367            }
    368            return false;
    369        }
    370        if (type instanceof WildcardType) {
    371            final WildcardType wild = (WildcardType) type;
    372            return containsTypeVariables(getImplicitLowerBounds(wild)[0])
    373                || containsTypeVariables(getImplicitUpperBounds(wild)[0]);
    374        }
    375        if (type instanceof GenericArrayType) {
    376            return containsTypeVariables(((GenericArrayType) type).getGenericComponentType());
    377        }
    378        return false;
    379    }
    380
    381    private static boolean containsVariableTypeSameParametrizedTypeBound(final TypeVariable<?> typeVariable,
    382        final ParameterizedType parameterizedType) {
    383        return ArrayUtils.contains(typeVariable.getBounds(), parameterizedType);
    384    }
    385
    386    /**
    387     * Tries to determine the type arguments of a class/interface based on a
    388     * super parameterized type's type arguments. This method is the inverse of
    389     * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
    390     * type arguments based on a subtype. It is far more limited in determining
    391     * the type arguments for the subject class's type variables in that it can
    392     * only determine those parameters that map from the subject {@link Class}
    393     * object to the supertype.
    394     *
    395     * <p>
    396     * Example: {@link java.util.TreeSet
    397     * TreeSet} sets its parameter as the parameter for
    398     * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
    399     * parameter of {@link java.util.SortedSet}, which in turn sets the
    400     * parameter of {@link Set}, which in turn sets the parameter of
    401     * {@link java.util.Collection}, which in turn sets the parameter of
    402     * {@link java.lang.Iterable}. Since {@code TreeSet}'s parameter maps
    403     * (indirectly) to {@code Iterable}'s parameter, it will be able to
    404     * determine that based on the super type {@code Iterable<? extends
    405     * Map<Integer, ? extends Collection<?>>>}, the parameter of
    406     * {@code TreeSet} is {@code ? extends Map<Integer, ? extends
    407     * Collection<?>>}.
    408     * </p>
    409     *
    410     * @param cls the class whose type parameters are to be determined, not {@code null}
    411     * @param superParameterizedType the super type from which {@code cls}'s type
    412     * arguments are to be determined, not {@code null}
    413     * @return a {@code Map} of the type assignments that could be determined
    414     * for the type variables in each type in the inheritance hierarchy from
    415     * {@code type} to {@code toClass} inclusive.
    416     */
    417    public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
    418            final ParameterizedType superParameterizedType) {
    419        Validate.notNull(cls, "cls");
    420        Validate.notNull(superParameterizedType, "superParameterizedType");
    421
    422        final Class<?> superClass = getRawType(superParameterizedType);
    423
    424        // compatibility check
    425        if (!isAssignable(cls, superClass)) {
    426            return null;
    427        }
    428
    429        if (cls.equals(superClass)) {
    430            return getTypeArguments(superParameterizedType, superClass, null);
    431        }
    432
    433        // get the next class in the inheritance hierarchy
    434        final Type midType = getClosestParentType(cls, superClass);
    435
    436        // can only be a class or a parameterized type
    437        if (midType instanceof Class<?>) {
    438            return determineTypeArguments((Class<?>) midType, superParameterizedType);
    439        }
    440
    441        final ParameterizedType midParameterizedType = (ParameterizedType) midType;
    442        final Class<?> midClass = getRawType(midParameterizedType);
    443        // get the type variables of the mid class that map to the type
    444        // arguments of the super class
    445        final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superParameterizedType);
    446        // map the arguments of the mid type to the class type variables
    447        mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
    448
    449        return typeVarAssigns;
    450    }
    451
    452    /**
    453     * Tests whether {@code t} equals {@code a}.
    454     *
    455     * @param genericArrayType LHS
    456     * @param type RHS
    457     * @return boolean
    458     * @since 3.2
    459     */
    460    private static boolean equals(final GenericArrayType genericArrayType, final Type type) {
    461        return type instanceof GenericArrayType
    462            && equals(genericArrayType.getGenericComponentType(), ((GenericArrayType) type).getGenericComponentType());
    463    }
    464
    465    /**
    466     * Tests whether {@code t} equals {@code p}.
    467     *
    468     * @param parameterizedType LHS
    469     * @param type RHS
    470     * @return boolean
    471     * @since 3.2
    472     */
    473    private static boolean equals(final ParameterizedType parameterizedType, final Type type) {
    474        if (type instanceof ParameterizedType) {
    475            final ParameterizedType other = (ParameterizedType) type;
    476            if (equals(parameterizedType.getRawType(), other.getRawType())
    477                && equals(parameterizedType.getOwnerType(), other.getOwnerType())) {
    478                return equals(parameterizedType.getActualTypeArguments(), other.getActualTypeArguments());
    479            }
    480        }
    481        return false;
    482    }
    483
    484    /**
    485     * Tests equality of types.
    486     *
    487     * @param type1 the first type
    488     * @param type2 the second type
    489     * @return boolean
    490     * @since 3.2
    491     */
    492    public static boolean equals(final Type type1, final Type type2) {
    493        if (Objects.equals(type1, type2)) {
    494            return true;
    495        }
    496        if (type1 instanceof ParameterizedType) {
    497            return equals((ParameterizedType) type1, type2);
    498        }
    499        if (type1 instanceof GenericArrayType) {
    500            return equals((GenericArrayType) type1, type2);
    501        }
    502        if (type1 instanceof WildcardType) {
    503            return equals((WildcardType) type1, type2);
    504        }
    505        return false;
    506    }
    507
    508    /**
    509     * Tests whether {@code t1} equals {@code t2}.
    510     *
    511     * @param type1 LHS
    512     * @param type2 RHS
    513     * @return boolean
    514     * @since 3.2
    515     */
    516    private static boolean equals(final Type[] type1, final Type[] type2) {
    517        if (type1.length == type2.length) {
    518            for (int i = 0; i < type1.length; i++) {
    519                if (!equals(type1[i], type2[i])) {
    520                    return false;
    521                }
    522            }
    523            return true;
    524        }
    525        return false;
    526    }
    527
    528    /**
    529     * Tests whether {@code t} equals {@code w}.
    530     *
    531     * @param wildcardType LHS
    532     * @param type RHS
    533     * @return boolean
    534     * @since 3.2
    535     */
    536    private static boolean equals(final WildcardType wildcardType, final Type type) {
    537        if (type instanceof WildcardType) {
    538            final WildcardType other = (WildcardType) type;
    539            return equals(getImplicitLowerBounds(wildcardType), getImplicitLowerBounds(other))
    540                && equals(getImplicitUpperBounds(wildcardType), getImplicitUpperBounds(other));
    541        }
    542        return false;
    543    }
    544
    545    /**
    546     * Helper method to establish the formal parameters for a parameterized type.
    547     *
    548     * @param mappings map containing the assignments
    549     * @param variables expected map keys
    550     * @return array of map values corresponding to specified keys
    551     */
    552    private static Type[] extractTypeArgumentsFrom(final Map<TypeVariable<?>, Type> mappings, final TypeVariable<?>[] variables) {
    553        final Type[] result = new Type[variables.length];
    554        int index = 0;
    555        for (final TypeVariable<?> var : variables) {
    556            Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var));
    557            result[index++] = mappings.get(var);
    558        }
    559        return result;
    560    }
    561
    562    private static int[] findRecursiveTypes(final ParameterizedType parameterizedType) {
    563        final Type[] filteredArgumentTypes = Arrays.copyOf(parameterizedType.getActualTypeArguments(),
    564            parameterizedType.getActualTypeArguments().length);
    565        int[] indexesToRemove = {};
    566        for (int i = 0; i < filteredArgumentTypes.length; i++) {
    567            if ((filteredArgumentTypes[i] instanceof TypeVariable<?>) && containsVariableTypeSameParametrizedTypeBound(
    568                ((TypeVariable<?>) filteredArgumentTypes[i]), parameterizedType)) {
    569                indexesToRemove = ArrayUtils.add(indexesToRemove, i);
    570            }
    571        }
    572        return indexesToRemove;
    573    }
    574
    575    /**
    576     * Creates a generic array type instance.
    577     *
    578     * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]}
    579     *                      is {@code boolean}
    580     * @return {@link GenericArrayType}
    581     * @since 3.2
    582     */
    583    public static GenericArrayType genericArrayType(final Type componentType) {
    584        return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType"));
    585    }
    586
    587    /**
    588     * Formats a {@link GenericArrayType} as a {@link String}.
    589     *
    590     * @param genericArrayType {@code GenericArrayType} to format
    591     * @return String
    592     * @since 3.2
    593     */
    594    private static String genericArrayTypeToString(final GenericArrayType genericArrayType) {
    595        return String.format("%s[]", toString(genericArrayType.getGenericComponentType()));
    596    }
    597
    598    /**
    599     * Gets the array component type of {@code type}.
    600     *
    601     * @param type the type to be checked
    602     * @return component type or null if type is not an array type
    603     */
    604    public static Type getArrayComponentType(final Type type) {
    605        if (type instanceof Class<?>) {
    606            final Class<?> cls = (Class<?>) type;
    607            return cls.isArray() ? cls.getComponentType() : null;
    608        }
    609        if (type instanceof GenericArrayType) {
    610            return ((GenericArrayType) type).getGenericComponentType();
    611        }
    612        return null;
    613    }
    614
    615    /**
    616     * Gets the closest parent type to the
    617     * super class specified by {@code superClass}.
    618     *
    619     * @param cls the class in question
    620     * @param superClass the super class
    621     * @return the closes parent type
    622     */
    623    private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
    624        // only look at the interfaces if the super class is also an interface
    625        if (superClass.isInterface()) {
    626            // get the generic interfaces of the subject class
    627            final Type[] interfaceTypes = cls.getGenericInterfaces();
    628            // will hold the best generic interface match found
    629            Type genericInterface = null;
    630
    631            // find the interface closest to the super class
    632            for (final Type midType : interfaceTypes) {
    633                Class<?> midClass = null;
    634
    635                if (midType instanceof ParameterizedType) {
    636                    midClass = getRawType((ParameterizedType) midType);
    637                } else if (midType instanceof Class<?>) {
    638                    midClass = (Class<?>) midType;
    639                } else {
    640                    throw new IllegalStateException("Unexpected generic"
    641                            + " interface type found: " + midType);
    642                }
    643
    644                // check if this interface is further up the inheritance chain
    645                // than the previously found match
    646                if (isAssignable(midClass, superClass)
    647                        && isAssignable(genericInterface, (Type) midClass)) {
    648                    genericInterface = midType;
    649                }
    650            }
    651
    652            // found a match?
    653            if (genericInterface != null) {
    654                return genericInterface;
    655            }
    656        }
    657
    658        // none of the interfaces were descendants of the target class, so the
    659        // super class has to be one, instead
    660        return cls.getGenericSuperclass();
    661    }
    662
    663    /**
    664     * Gets an array containing the sole type of {@link Object} if
    665     * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
    666     * returns the result of {@link TypeVariable#getBounds()} passed into
    667     * {@link #normalizeUpperBounds}.
    668     *
    669     * @param typeVariable the subject type variable, not {@code null}
    670     * @return a non-empty array containing the bounds of the type variable.
    671     */
    672    public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
    673        Validate.notNull(typeVariable, "typeVariable");
    674        final Type[] bounds = typeVariable.getBounds();
    675
    676        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
    677    }
    678
    679    /**
    680     * Gets an array containing a single value of {@code null} if
    681     * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
    682     * it returns the result of {@link WildcardType#getLowerBounds()}.
    683     *
    684     * @param wildcardType the subject wildcard type, not {@code null}
    685     * @return a non-empty array containing the lower bounds of the wildcard
    686     * type.
    687     */
    688    public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
    689        Validate.notNull(wildcardType, "wildcardType");
    690        final Type[] bounds = wildcardType.getLowerBounds();
    691
    692        return bounds.length == 0 ? new Type[] { null } : bounds;
    693    }
    694
    695    /**
    696     * Gets an array containing the sole value of {@link Object} if
    697     * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
    698     * it returns the result of {@link WildcardType#getUpperBounds()}
    699     * passed into {@link #normalizeUpperBounds}.
    700     *
    701     * @param wildcardType the subject wildcard type, not {@code null}
    702     * @return a non-empty array containing the upper bounds of the wildcard
    703     * type.
    704     */
    705    public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
    706        Validate.notNull(wildcardType, "wildcardType");
    707        final Type[] bounds = wildcardType.getUpperBounds();
    708
    709        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
    710    }
    711
    712    /**
    713     * Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.
    714     *
    715     * @param parameterizedType the type to be converted
    716     * @return the corresponding {@code Class} object
    717     * @throws IllegalStateException if the conversion fails
    718     */
    719    private static Class<?> getRawType(final ParameterizedType parameterizedType) {
    720        final Type rawType = parameterizedType.getRawType();
    721
    722        // check if raw type is a Class object
    723        // not currently necessary, but since the return type is Type instead of
    724        // Class, there's enough reason to believe that future versions of Java
    725        // may return other Type implementations. And type-safety checking is
    726        // rarely a bad idea.
    727        if (!(rawType instanceof Class<?>)) {
    728            throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
    729        }
    730
    731        return (Class<?>) rawType;
    732    }
    733
    734    /**
    735     * Gets the raw type of a Java type, given its context. Primarily for use
    736     * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
    737     * not know the runtime type of {@code type}: if you know you have a
    738     * {@link Class} instance, it is already raw; if you know you have a
    739     * {@link ParameterizedType}, its raw type is only a method call away.
    740     *
    741     * @param type to resolve
    742     * @param assigningType type to be resolved against
    743     * @return the resolved {@link Class} object or {@code null} if
    744     * the type could not be resolved
    745     */
    746    public static Class<?> getRawType(final Type type, final Type assigningType) {
    747        if (type instanceof Class<?>) {
    748            // it is raw, no problem
    749            return (Class<?>) type;
    750        }
    751
    752        if (type instanceof ParameterizedType) {
    753            // simple enough to get the raw type of a ParameterizedType
    754            return getRawType((ParameterizedType) type);
    755        }
    756
    757        if (type instanceof TypeVariable<?>) {
    758            if (assigningType == null) {
    759                return null;
    760            }
    761
    762            // get the entity declaring this type variable
    763            final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
    764
    765            // can't get the raw type of a method- or constructor-declared type
    766            // variable
    767            if (!(genericDeclaration instanceof Class<?>)) {
    768                return null;
    769            }
    770
    771            // get the type arguments for the declaring class/interface based
    772            // on the enclosing type
    773            final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
    774                    (Class<?>) genericDeclaration);
    775
    776            // enclosingType has to be a subclass (or subinterface) of the
    777            // declaring type
    778            if (typeVarAssigns == null) {
    779                return null;
    780            }
    781
    782            // get the argument assigned to this type variable
    783            final Type typeArgument = typeVarAssigns.get(type);
    784
    785            if (typeArgument == null) {
    786                return null;
    787            }
    788
    789            // get the argument for this type variable
    790            return getRawType(typeArgument, assigningType);
    791        }
    792
    793        if (type instanceof GenericArrayType) {
    794            // get raw component type
    795            final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
    796                    .getGenericComponentType(), assigningType);
    797
    798            // create array type from raw component type and return its class
    799            return Array.newInstance(rawComponentType, 0).getClass();
    800        }
    801
    802        // (hand-waving) this is not the method you're looking for
    803        if (type instanceof WildcardType) {
    804            return null;
    805        }
    806
    807        throw new IllegalArgumentException("unknown type: " + type);
    808    }
    809
    810    /**
    811     * Gets a map of the type arguments of a class in the context of {@code toClass}.
    812     *
    813     * @param cls the class in question
    814     * @param toClass the context class
    815     * @param subtypeVarAssigns a map with type variables
    816     * @return the {@code Map} with type arguments
    817     */
    818    private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
    819            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
    820        // make sure they're assignable
    821        if (!isAssignable(cls, toClass)) {
    822            return null;
    823        }
    824
    825        // can't work with primitives
    826        if (cls.isPrimitive()) {
    827            // both classes are primitives?
    828            if (toClass.isPrimitive()) {
    829                // dealing with widening here. No type arguments to be
    830                // harvested with these two types.
    831                return new HashMap<>();
    832            }
    833
    834            // work with wrapper the wrapper class instead of the primitive
    835            cls = ClassUtils.primitiveToWrapper(cls);
    836        }
    837
    838        // create a copy of the incoming map, or an empty one if it's null
    839        final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
    840                : new HashMap<>(subtypeVarAssigns);
    841
    842        // has target class been reached?
    843        if (toClass.equals(cls)) {
    844            return typeVarAssigns;
    845        }
    846
    847        // walk the inheritance hierarchy until the target class is reached
    848        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
    849    }
    850
    851    /**
    852     * Gets all the type arguments for this parameterized type
    853     * including owner hierarchy arguments such as
    854     * {@code Outer<K, V>.Inner<T>.DeepInner<E>} .
    855     * The arguments are returned in a
    856     * {@link Map} specifying the argument type for each {@link TypeVariable}.
    857     *
    858     * @param type specifies the subject parameterized type from which to
    859     *             harvest the parameters.
    860     * @return a {@code Map} of the type arguments to their respective type
    861     * variables.
    862     */
    863    public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
    864        return getTypeArguments(type, getRawType(type), null);
    865    }
    866
    867    /**
    868     * Gets a map of the type arguments of a parameterized type in the context of {@code toClass}.
    869     *
    870     * @param parameterizedType the parameterized type
    871     * @param toClass the class
    872     * @param subtypeVarAssigns a map with type variables
    873     * @return the {@code Map} with type arguments
    874     */
    875    private static Map<TypeVariable<?>, Type> getTypeArguments(
    876            final ParameterizedType parameterizedType, final Class<?> toClass,
    877            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
    878        final Class<?> cls = getRawType(parameterizedType);
    879
    880        // make sure they're assignable
    881        if (!isAssignable(cls, toClass)) {
    882            return null;
    883        }
    884
    885        final Type ownerType = parameterizedType.getOwnerType();
    886        final Map<TypeVariable<?>, Type> typeVarAssigns;
    887
    888        if (ownerType instanceof ParameterizedType) {
    889            // get the owner type arguments first
    890            final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
    891            typeVarAssigns = getTypeArguments(parameterizedOwnerType,
    892                    getRawType(parameterizedOwnerType), subtypeVarAssigns);
    893        } else {
    894            // no owner, prep the type variable assignments map
    895            typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
    896                    : new HashMap<>(subtypeVarAssigns);
    897        }
    898
    899        // get the subject parameterized type's arguments
    900        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
    901        // and get the corresponding type variables from the raw class
    902        final TypeVariable<?>[] typeParams = cls.getTypeParameters();
    903
    904        // map the arguments to their respective type variables
    905        for (int i = 0; i < typeParams.length; i++) {
    906            final Type typeArg = typeArgs[i];
    907            typeVarAssigns.put(
    908                    typeParams[i],
    909                    typeVarAssigns.getOrDefault(typeArg, typeArg)
    910            );
    911        }
    912
    913        if (toClass.equals(cls)) {
    914            // target class has been reached. Done.
    915            return typeVarAssigns;
    916        }
    917
    918        // walk the inheritance hierarchy until the target class is reached
    919        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
    920    }
    921
    922    /**
    923     * Gets the type arguments of a class/interface based on a subtype. For
    924     * instance, this method will determine that both of the parameters for the
    925     * interface {@link Map} are {@link Object} for the subtype
    926     * {@link java.util.Properties Properties} even though the subtype does not
    927     * directly implement the {@code Map} interface.
    928     *
    929     * <p>
    930     * This method returns {@code null} if {@code type} is not assignable to
    931     * {@code toClass}. It returns an empty map if none of the classes or
    932     * interfaces in its inheritance hierarchy specify any type arguments.
    933     * </p>
    934     *
    935     * <p>
    936     * A side effect of this method is that it also retrieves the type
    937     * arguments for the classes and interfaces that are part of the hierarchy
    938     * between {@code type} and {@code toClass}. So with the above
    939     * example, this method will also determine that the type arguments for
    940     * {@link java.util.Hashtable Hashtable} are also both {@code Object}.
    941     * In cases where the interface specified by {@code toClass} is
    942     * (indirectly) implemented more than once (e.g. where {@code toClass}
    943     * specifies the interface {@link java.lang.Iterable Iterable} and
    944     * {@code type} specifies a parameterized type that implements both
    945     * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
    946     * this method will look at the inheritance hierarchy of only one of the
    947     * implementations/subclasses; the first interface encountered that isn't a
    948     * subinterface to one of the others in the {@code type} to
    949     * {@code toClass} hierarchy.
    950     * </p>
    951     *
    952     * @param type the type from which to determine the type parameters of
    953     * {@code toClass}
    954     * @param toClass the class whose type parameters are to be determined based
    955     * on the subtype {@code type}
    956     * @return a {@code Map} of the type assignments for the type variables in
    957     * each type in the inheritance hierarchy from {@code type} to
    958     * {@code toClass} inclusive.
    959     */
    960    public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
    961        return getTypeArguments(type, toClass, null);
    962    }
    963
    964    /**
    965     * Gets a map of the type arguments of {@code type} in the context of {@code toClass}.
    966     *
    967     * @param type the type in question
    968     * @param toClass the class
    969     * @param subtypeVarAssigns a map with type variables
    970     * @return the {@code Map} with type arguments
    971     */
    972    private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass,
    973            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
    974        if (type instanceof Class<?>) {
    975            return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
    976        }
    977
    978        if (type instanceof ParameterizedType) {
    979            return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
    980        }
    981
    982        if (type instanceof GenericArrayType) {
    983            return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
    984                    .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
    985        }
    986
    987        // since wildcard types are not assignable to classes, should this just
    988        // return null?
    989        if (type instanceof WildcardType) {
    990            for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
    991                // find the first bound that is assignable to the target class
    992                if (isAssignable(bound, toClass)) {
    993                    return getTypeArguments(bound, toClass, subtypeVarAssigns);
    994                }
    995            }
    996
    997            return null;
    998        }
    999
    1000        if (type instanceof TypeVariable<?>) {
    1001            for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
    1002                // find the first bound that is assignable to the target class
    1003                if (isAssignable(bound, toClass)) {
    1004                    return getTypeArguments(bound, toClass, subtypeVarAssigns);
    1005                }
    1006            }
    1007
    1008            return null;
    1009        }
    1010        throw new IllegalStateException("found an unhandled type: " + type);
    1011    }
    1012
    1013    /**
    1014     * Tests whether the specified type denotes an array type.
    1015     *
    1016     * @param type the type to be checked
    1017     * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}.
    1018     */
    1019    public static boolean isArrayType(final Type type) {
    1020        return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
    1021    }
    1022
    1023    /**
    1024     * Tests if the subject type may be implicitly cast to the target class
    1025     * following the Java generics rules.
    1026     *
    1027     * @param type the subject type to be assigned to the target type
    1028     * @param toClass the target class
    1029     * @return {@code true} if {@code type} is assignable to {@code toClass}.
    1030     */
    1031    private static boolean isAssignable(final Type type, final Class<?> toClass) {
    1032        if (type == null) {
    1033            // consistency with ClassUtils.isAssignable() behavior
    1034            return toClass == null || !toClass.isPrimitive();
    1035        }
    1036
    1037        // only a null type can be assigned to null type which
    1038        // would have cause the previous to return true
    1039        if (toClass == null) {
    1040            return false;
    1041        }
    1042
    1043        // all types are assignable to themselves
    1044        if (toClass.equals(type)) {
    1045            return true;
    1046        }
    1047
    1048        if (type instanceof Class<?>) {
    1049            // just comparing two classes
    1050            return ClassUtils.isAssignable((Class<?>) type, toClass);
    1051        }
    1052
    1053        if (type instanceof ParameterizedType) {
    1054            // only have to compare the raw type to the class
    1055            return isAssignable(getRawType((ParameterizedType) type), toClass);
    1056        }
    1057
    1058        // *
    1059        if (type instanceof TypeVariable<?>) {
    1060            // if any of the bounds are assignable to the class, then the
    1061            // type is assignable to the class.
    1062            for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
    1063                if (isAssignable(bound, toClass)) {
    1064                    return true;
    1065                }
    1066            }
    1067
    1068            return false;
    1069        }
    1070
    1071        // the only classes to which a generic array type can be assigned
    1072        // are class Object and array classes
    1073        if (type instanceof GenericArrayType) {
    1074            return toClass.equals(Object.class)
    1075                    || toClass.isArray()
    1076                    && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
    1077                            .getComponentType());
    1078        }
    1079
    1080        // wildcard types are not assignable to a class (though one would think
    1081        // "? super Object" would be assignable to Object)
    1082        if (type instanceof WildcardType) {
    1083            return false;
    1084        }
    1085
    1086        throw new IllegalStateException("found an unhandled type: " + type);
    1087    }
    1088
    1089    /**
    1090     * Tests if the subject type may be implicitly cast to the target
    1091     * generic array type following the Java generics rules.
    1092     *
    1093     * @param type the subject type to be assigned to the target type
    1094     * @param toGenericArrayType the target generic array type
    1095     * @param typeVarAssigns a map with type variables
    1096     * @return {@code true} if {@code type} is assignable to
    1097     * {@code toGenericArrayType}.
    1098     */
    1099    private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
    1100            final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1101        if (type == null) {
    1102            return true;
    1103        }
    1104
    1105        // only a null type can be assigned to null type which
    1106        // would have cause the previous to return true
    1107        if (toGenericArrayType == null) {
    1108            return false;
    1109        }
    1110
    1111        // all types are assignable to themselves
    1112        if (toGenericArrayType.equals(type)) {
    1113            return true;
    1114        }
    1115
    1116        final Type toComponentType = toGenericArrayType.getGenericComponentType();
    1117
    1118        if (type instanceof Class<?>) {
    1119            final Class<?> cls = (Class<?>) type;
    1120
    1121            // compare the component types
    1122            return cls.isArray()
    1123                    && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
    1124        }
    1125
    1126        if (type instanceof GenericArrayType) {
    1127            // compare the component types
    1128            return isAssignable(((GenericArrayType) type).getGenericComponentType(),
    1129                    toComponentType, typeVarAssigns);
    1130        }
    1131
    1132        if (type instanceof WildcardType) {
    1133            // so long as one of the upper bounds is assignable, it's good
    1134            for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
    1135                if (isAssignable(bound, toGenericArrayType)) {
    1136                    return true;
    1137                }
    1138            }
    1139
    1140            return false;
    1141        }
    1142
    1143        if (type instanceof TypeVariable<?>) {
    1144            // probably should remove the following logic and just return false.
    1145            // type variables cannot specify arrays as bounds.
    1146            for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
    1147                if (isAssignable(bound, toGenericArrayType)) {
    1148                    return true;
    1149                }
    1150            }
    1151
    1152            return false;
    1153        }
    1154
    1155        if (type instanceof ParameterizedType) {
    1156            // the raw type of a parameterized type is never an array or
    1157            // generic array, otherwise the declaration would look like this:
    1158            // Collection[]< ? extends String > collection;
    1159            return false;
    1160        }
    1161
    1162        throw new IllegalStateException("found an unhandled type: " + type);
    1163    }
    1164
    1165    /**
    1166     * Tests if the subject type may be implicitly cast to the target
    1167     * parameterized type following the Java generics rules.
    1168     *
    1169     * @param type the subject type to be assigned to the target type
    1170     * @param toParameterizedType the target parameterized type
    1171     * @param typeVarAssigns a map with type variables
    1172     * @return {@code true} if {@code type} is assignable to {@code toType}.
    1173     */
    1174    private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
    1175            final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1176        if (type == null) {
    1177            return true;
    1178        }
    1179
    1180        // only a null type can be assigned to null type which
    1181        // would have cause the previous to return true
    1182        if (toParameterizedType == null) {
    1183            return false;
    1184        }
    1185
    1186        // cannot cast an array type to a parameterized type.
    1187        if (type instanceof GenericArrayType) {
    1188            return false;
    1189        }
    1190
    1191        // all types are assignable to themselves
    1192        if (toParameterizedType.equals(type)) {
    1193            return true;
    1194        }
    1195
    1196        // get the target type's raw type
    1197        final Class<?> toClass = getRawType(toParameterizedType);
    1198        // get the subject type's type arguments including owner type arguments
    1199        // and supertype arguments up to and including the target class.
    1200        final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
    1201
    1202        // null means the two types are not compatible
    1203        if (fromTypeVarAssigns == null) {
    1204            return false;
    1205        }
    1206
    1207        // compatible types, but there's no type arguments. this is equivalent
    1208        // to comparing Map< ?, ? > to Map, and raw types are always assignable
    1209        // to parameterized types.
    1210        if (fromTypeVarAssigns.isEmpty()) {
    1211            return true;
    1212        }
    1213
    1214        // get the target type's type arguments including owner type arguments
    1215        final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
    1216                toClass, typeVarAssigns);
    1217
    1218        // now to check each type argument
    1219        for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
    1220            final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
    1221            final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
    1222
    1223            if (toTypeArg == null && fromTypeArg instanceof Class) {
    1224                continue;
    1225            }
    1226
    1227            // parameters must either be absent from the subject type, within
    1228            // the bounds of the wildcard type, or be an exact match to the
    1229            // parameters of the target type.
    1230            if (fromTypeArg != null && toTypeArg != null
    1231                    && !toTypeArg.equals(fromTypeArg)
    1232                    && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
    1233                            typeVarAssigns))) {
    1234                return false;
    1235            }
    1236        }
    1237        return true;
    1238    }
    1239
    1240    /**
    1241     * Tests if the subject type may be implicitly cast to the target type
    1242     * following the Java generics rules. If both types are {@link Class}
    1243     * objects, the method returns the result of
    1244     * {@link ClassUtils#isAssignable(Class, Class)}.
    1245     *
    1246     * @param type the subject type to be assigned to the target type
    1247     * @param toType the target type
    1248     * @return {@code true} if {@code type} is assignable to {@code toType}.
    1249     */
    1250    public static boolean isAssignable(final Type type, final Type toType) {
    1251        return isAssignable(type, toType, null);
    1252    }
    1253
    1254    /**
    1255     * Tests if the subject type may be implicitly cast to the target type
    1256     * following the Java generics rules.
    1257     *
    1258     * @param type the subject type to be assigned to the target type
    1259     * @param toType the target type
    1260     * @param typeVarAssigns optional map of type variable assignments
    1261     * @return {@code true} if {@code type} is assignable to {@code toType}.
    1262     */
    1263    private static boolean isAssignable(final Type type, final Type toType,
    1264            final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1265        if (toType == null || toType instanceof Class<?>) {
    1266            return isAssignable(type, (Class<?>) toType);
    1267        }
    1268
    1269        if (toType instanceof ParameterizedType) {
    1270            return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
    1271        }
    1272
    1273        if (toType instanceof GenericArrayType) {
    1274            return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
    1275        }
    1276
    1277        if (toType instanceof WildcardType) {
    1278            return isAssignable(type, (WildcardType) toType, typeVarAssigns);
    1279        }
    1280
    1281        if (toType instanceof TypeVariable<?>) {
    1282            return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
    1283        }
    1284
    1285        throw new IllegalStateException("found an unhandled type: " + toType);
    1286    }
    1287
    1288    /**
    1289     * Tests if the subject type may be implicitly cast to the target type
    1290     * variable following the Java generics rules.
    1291     *
    1292     * @param type the subject type to be assigned to the target type
    1293     * @param toTypeVariable the target type variable
    1294     * @param typeVarAssigns a map with type variables
    1295     * @return {@code true} if {@code type} is assignable to
    1296     * {@code toTypeVariable}.
    1297     */
    1298    private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
    1299            final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1300        if (type == null) {
    1301            return true;
    1302        }
    1303
    1304        // only a null type can be assigned to null type which
    1305        // would have cause the previous to return true
    1306        if (toTypeVariable == null) {
    1307            return false;
    1308        }
    1309
    1310        // all types are assignable to themselves
    1311        if (toTypeVariable.equals(type)) {
    1312            return true;
    1313        }
    1314
    1315        if (type instanceof TypeVariable<?>) {
    1316            // a type variable is assignable to another type variable, if
    1317            // and only if the former is the latter, extends the latter, or
    1318            // is otherwise a descendant of the latter.
    1319            final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
    1320
    1321            for (final Type bound : bounds) {
    1322                if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
    1323                    return true;
    1324                }
    1325            }
    1326        }
    1327
    1328        if (type instanceof Class<?> || type instanceof ParameterizedType
    1329                || type instanceof GenericArrayType || type instanceof WildcardType) {
    1330            return false;
    1331        }
    1332
    1333        throw new IllegalStateException("found an unhandled type: " + type);
    1334    }
    1335
    1336    /**
    1337     * Tests if the subject type may be implicitly cast to the target
    1338     * wildcard type following the Java generics rules.
    1339     *
    1340     * @param type the subject type to be assigned to the target type
    1341     * @param toWildcardType the target wildcard type
    1342     * @param typeVarAssigns a map with type variables
    1343     * @return {@code true} if {@code type} is assignable to
    1344     * {@code toWildcardType}.
    1345     */
    1346    private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
    1347            final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1348        if (type == null) {
    1349            return true;
    1350        }
    1351
    1352        // only a null type can be assigned to null type which
    1353        // would have cause the previous to return true
    1354        if (toWildcardType == null) {
    1355            return false;
    1356        }
    1357
    1358        // all types are assignable to themselves
    1359        if (toWildcardType.equals(type)) {
    1360            return true;
    1361        }
    1362
    1363        final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
    1364        final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
    1365
    1366        if (type instanceof WildcardType) {
    1367            final WildcardType wildcardType = (WildcardType) type;
    1368            final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
    1369            final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
    1370
    1371            for (Type toBound : toUpperBounds) {
    1372                // if there are assignments for unresolved type variables,
    1373                // now's the time to substitute them.
    1374                toBound = substituteTypeVariables(toBound, typeVarAssigns);
    1375
    1376                // each upper bound of the subject type has to be assignable to
    1377                // each
    1378                // upper bound of the target type
    1379                for (final Type bound : upperBounds) {
    1380                    if (!isAssignable(bound, toBound, typeVarAssigns)) {
    1381                        return false;
    1382                    }
    1383                }
    1384            }
    1385
    1386            for (Type toBound : toLowerBounds) {
    1387                // if there are assignments for unresolved type variables,
    1388                // now's the time to substitute them.
    1389                toBound = substituteTypeVariables(toBound, typeVarAssigns);
    1390
    1391                // each lower bound of the target type has to be assignable to
    1392                // each
    1393                // lower bound of the subject type
    1394                for (final Type bound : lowerBounds) {
    1395                    if (!isAssignable(toBound, bound, typeVarAssigns)) {
    1396                        return false;
    1397                    }
    1398                }
    1399            }
    1400            return true;
    1401        }
    1402
    1403        for (final Type toBound : toUpperBounds) {
    1404            // if there are assignments for unresolved type variables,
    1405            // now's the time to substitute them.
    1406            if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
    1407                    typeVarAssigns)) {
    1408                return false;
    1409            }
    1410        }
    1411
    1412        for (final Type toBound : toLowerBounds) {
    1413            // if there are assignments for unresolved type variables,
    1414            // now's the time to substitute them.
    1415            if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
    1416                    typeVarAssigns)) {
    1417                return false;
    1418            }
    1419        }
    1420        return true;
    1421    }
    1422
    1423    /**
    1424     * Tests if the given value can be assigned to the target type
    1425     * following the Java generics rules.
    1426     *
    1427     * @param value the value to be checked
    1428     * @param type the target type
    1429     * @return {@code true} if {@code value} is an instance of {@code type}.
    1430     */
    1431    public static boolean isInstance(final Object value, final Type type) {
    1432        if (type == null) {
    1433            return false;
    1434        }
    1435
    1436        return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
    1437                : isAssignable(value.getClass(), type, null);
    1438    }
    1439
    1440    /**
    1441     * Maps type variables.
    1442     *
    1443     * @param <T> the generic type of the class in question
    1444     * @param cls the class in question
    1445     * @param parameterizedType the parameterized type
    1446     * @param typeVarAssigns the map to be filled
    1447     */
    1448    private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
    1449            final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1450        // capture the type variables from the owner type that have assignments
    1451        final Type ownerType = parameterizedType.getOwnerType();
    1452
    1453        if (ownerType instanceof ParameterizedType) {
    1454            // recursion to make sure the owner's owner type gets processed
    1455            mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
    1456        }
    1457
    1458        // parameterizedType is a generic interface/class (or it's in the owner
    1459        // hierarchy of said interface/class) implemented/extended by the class
    1460        // cls. Find out which type variables of cls are type arguments of
    1461        // parameterizedType:
    1462        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
    1463
    1464        // of the cls's type variables that are arguments of parameterizedType,
    1465        // find out which ones can be determined from the super type's arguments
    1466        final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
    1467
    1468        // use List view of type parameters of cls so the contains() method can be used:
    1469        final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
    1470                .getTypeParameters());
    1471
    1472        for (int i = 0; i < typeArgs.length; i++) {
    1473            final TypeVariable<?> typeVar = typeVars[i];
    1474            final Type typeArg = typeArgs[i];
    1475
    1476            // argument of parameterizedType is a type variable of cls
    1477            if (typeVarList.contains(typeArg)
    1478            // type variable of parameterizedType has an assignment in
    1479                    // the super type.
    1480                    && typeVarAssigns.containsKey(typeVar)) {
    1481                // map the assignment to the cls's type variable
    1482                typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
    1483            }
    1484        }
    1485    }
    1486
    1487    /**
    1488     * Strips out the redundant upper bound types in type
    1489     * variable types and wildcard types (or it would with wildcard types if
    1490     * multiple upper bounds were allowed).
    1491     *
    1492     * <p>
    1493     * Example, with the variable type declaration:
    1494     * </p>
    1495     *
    1496     * <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
    1497     * java.util.List&lt;String&gt;&gt;</pre>
    1498     *
    1499     * <p>
    1500     * since {@code List} is a subinterface of {@code Collection},
    1501     * this method will return the bounds as if the declaration had been:
    1502     * </p>
    1503     *
    1504     * <pre>&lt;K extends java.util.List&lt;String&gt;&gt;</pre>
    1505     *
    1506     * @param bounds an array of types representing the upper bounds of either
    1507     * {@link WildcardType} or {@link TypeVariable}, not {@code null}.
    1508     * @return an array containing the values from {@code bounds} minus the
    1509     * redundant types.
    1510     */
    1511    public static Type[] normalizeUpperBounds(final Type[] bounds) {
    1512        Validate.notNull(bounds, "bounds");
    1513        // don't bother if there's only one (or none) type
    1514        if (bounds.length < 2) {
    1515            return bounds;
    1516        }
    1517
    1518        final Set<Type> types = new HashSet<>(bounds.length);
    1519
    1520        for (final Type type1 : bounds) {
    1521            boolean subtypeFound = false;
    1522
    1523            for (final Type type2 : bounds) {
    1524                if (type1 != type2 && isAssignable(type2, type1, null)) {
    1525                    subtypeFound = true;
    1526                    break;
    1527                }
    1528            }
    1529
    1530            if (!subtypeFound) {
    1531                types.add(type1);
    1532            }
    1533        }
    1534
    1535        return types.toArray(ArrayUtils.EMPTY_TYPE_ARRAY);
    1536    }
    1537
    1538    /**
    1539     * Creates a parameterized type instance.
    1540     *
    1541     * @param rawClass the raw class to create a parameterized type instance for
    1542     * @param typeVariableMap the map used for parameterization
    1543     * @return {@link ParameterizedType}
    1544     * @since 3.2
    1545     */
    1546    public static final ParameterizedType parameterize(final Class<?> rawClass,
    1547        final Map<TypeVariable<?>, Type> typeVariableMap) {
    1548        Validate.notNull(rawClass, "rawClass");
    1549        Validate.notNull(typeVariableMap, "typeVariableMap");
    1550        return parameterizeWithOwner(null, rawClass,
    1551            extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
    1552    }
    1553
    1554    /**
    1555     * Creates a parameterized type instance.
    1556     *
    1557     * @param rawClass the raw class to create a parameterized type instance for
    1558     * @param typeArguments the types used for parameterization
    1559     * @return {@link ParameterizedType}
    1560     * @since 3.2
    1561     */
    1562    public static final ParameterizedType parameterize(final Class<?> rawClass, final Type... typeArguments) {
    1563        return parameterizeWithOwner(null, rawClass, typeArguments);
    1564    }
    1565
    1566    /**
    1567     * Formats a {@link ParameterizedType} as a {@link String}.
    1568     *
    1569     * @param parameterizedType {@code ParameterizedType} to format
    1570     * @return String
    1571     * @since 3.2
    1572     */
    1573    private static String parameterizedTypeToString(final ParameterizedType parameterizedType) {
    1574        final StringBuilder builder = new StringBuilder();
    1575
    1576        final Type useOwner = parameterizedType.getOwnerType();
    1577        final Class<?> raw = (Class<?>) parameterizedType.getRawType();
    1578
    1579        if (useOwner == null) {
    1580            builder.append(raw.getName());
    1581        } else {
    1582            if (useOwner instanceof Class<?>) {
    1583                builder.append(((Class<?>) useOwner).getName());
    1584            } else {
    1585                builder.append(useOwner.toString());
    1586            }
    1587            builder.append('.').append(raw.getSimpleName());
    1588        }
    1589
    1590        final int[] recursiveTypeIndexes = findRecursiveTypes(parameterizedType);
    1591
    1592        if (recursiveTypeIndexes.length > 0) {
    1593            appendRecursiveTypes(builder, recursiveTypeIndexes, parameterizedType.getActualTypeArguments());
    1594        } else {
    1595            appendAllTo(builder.append('<'), ", ", parameterizedType.getActualTypeArguments()).append('>');
    1596        }
    1597
    1598        return builder.toString();
    1599    }
    1600
    1601    /**
    1602     * Creates a parameterized type instance.
    1603     *
    1604     * @param owner the owning type
    1605     * @param rawClass the raw class to create a parameterized type instance for
    1606     * @param typeVariableMap the map used for parameterization
    1607     * @return {@link ParameterizedType}
    1608     * @since 3.2
    1609     */
    1610    public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
    1611        final Map<TypeVariable<?>, Type> typeVariableMap) {
    1612        Validate.notNull(rawClass, "rawClass");
    1613        Validate.notNull(typeVariableMap, "typeVariableMap");
    1614        return parameterizeWithOwner(owner, rawClass,
    1615            extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
    1616    }
    1617
    1618    /**
    1619     * Creates a parameterized type instance.
    1620     *
    1621     * @param owner the owning type
    1622     * @param rawClass the raw class to create a parameterized type instance for
    1623     * @param typeArguments the types used for parameterization
    1624     *
    1625     * @return {@link ParameterizedType}
    1626     * @since 3.2
    1627     */
    1628    public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
    1629        final Type... typeArguments) {
    1630        Validate.notNull(rawClass, "rawClass");
    1631        final Type useOwner;
    1632        if (rawClass.getEnclosingClass() == null) {
    1633            Validate.isTrue(owner == null, "no owner allowed for top-level %s", rawClass);
    1634            useOwner = null;
    1635        } else if (owner == null) {
    1636            useOwner = rawClass.getEnclosingClass();
    1637        } else {
    1638            Validate.isTrue(isAssignable(owner, rawClass.getEnclosingClass()),
    1639                "%s is invalid owner type for parameterized %s", owner, rawClass);
    1640            useOwner = owner;
    1641        }
    1642        Validate.noNullElements(typeArguments, "null type argument at index %s");
    1643        Validate.isTrue(rawClass.getTypeParameters().length == typeArguments.length,
    1644            "invalid number of type parameters specified: expected %d, got %d", rawClass.getTypeParameters().length,
    1645            typeArguments.length);
    1646
    1647        return new ParameterizedTypeImpl(rawClass, useOwner, typeArguments);
    1648    }
    1649
    1650    /**
    1651     * Finds the mapping for {@code type} in {@code typeVarAssigns}.
    1652     *
    1653     * @param type the type to be replaced
    1654     * @param typeVarAssigns the map with type variables
    1655     * @return the replaced type
    1656     * @throws IllegalArgumentException if the type cannot be substituted
    1657     */
    1658    private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1659        if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
    1660            final Type replacementType = typeVarAssigns.get(type);
    1661
    1662            if (replacementType == null) {
    1663                throw new IllegalArgumentException("missing assignment type for type variable "
    1664                        + type);
    1665            }
    1666            return replacementType;
    1667        }
    1668        return type;
    1669    }
    1670
    1671    /**
    1672     * Formats a {@link TypeVariable} including its {@link GenericDeclaration}.
    1673     *
    1674     * @param typeVariable the type variable to create a String representation for, not {@code null}
    1675     * @return String
    1676     * @since 3.2
    1677     */
    1678    public static String toLongString(final TypeVariable<?> typeVariable) {
    1679        Validate.notNull(typeVariable, "typeVariable");
    1680        final StringBuilder buf = new StringBuilder();
    1681        final GenericDeclaration d = typeVariable.getGenericDeclaration();
    1682        if (d instanceof Class<?>) {
    1683            Class<?> c = (Class<?>) d;
    1684            while (true) {
    1685                if (c.getEnclosingClass() == null) {
    1686                    buf.insert(0, c.getName());
    1687                    break;
    1688                }
    1689                buf.insert(0, c.getSimpleName()).insert(0, '.');
    1690                c = c.getEnclosingClass();
    1691            }
    1692        } else if (d instanceof Type) {// not possible as of now
    1693            buf.append(toString((Type) d));
    1694        } else {
    1695            buf.append(d);
    1696        }
    1697        return buf.append(':').append(typeVariableToString(typeVariable)).toString();
    1698    }
    1699
    1700    private static <T> String toString(final T object) {
    1701        return object instanceof Type ? toString((Type) object) : object.toString();
    1702    }
    1703
    1704    /**
    1705     * Formats a given type as a Java-esque String.
    1706     *
    1707     * @param type the type to create a String representation for, not {@code null}
    1708     * @return String
    1709     * @since 3.2
    1710     */
    1711    public static String toString(final Type type) {
    1712        Validate.notNull(type);
    1713        if (type instanceof Class<?>) {
    1714            return classToString((Class<?>) type);
    1715        }
    1716        if (type instanceof ParameterizedType) {
    1717            return parameterizedTypeToString((ParameterizedType) type);
    1718        }
    1719        if (type instanceof WildcardType) {
    1720            return wildcardTypeToString((WildcardType) type);
    1721        }
    1722        if (type instanceof TypeVariable<?>) {
    1723            return typeVariableToString((TypeVariable<?>) type);
    1724        }
    1725        if (type instanceof GenericArrayType) {
    1726            return genericArrayTypeToString((GenericArrayType) type);
    1727        }
    1728        throw new IllegalArgumentException(ObjectUtils.identityToString(type));
    1729    }
    1730
    1731    /**
    1732     * Determines whether or not specified types satisfy the bounds of their
    1733     * mapped type variables. When a type parameter extends another (such as
    1734     * {@code <T, S extends T>}), uses another as a type parameter (such as
    1735     * {@code <T, S extends Comparable>>}), or otherwise depends on
    1736     * another type variable to be specified, the dependencies must be included
    1737     * in {@code typeVarAssigns}.
    1738     *
    1739     * @param typeVariableMap specifies the potential types to be assigned to the
    1740     * type variables, not {@code null}.
    1741     * @return whether or not the types can be assigned to their respective type
    1742     * variables.
    1743     */
    1744    public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVariableMap) {
    1745        Validate.notNull(typeVariableMap, "typeVariableMap");
    1746        // all types must be assignable to all the bounds of their mapped
    1747        // type variable.
    1748        for (final Map.Entry<TypeVariable<?>, Type> entry : typeVariableMap.entrySet()) {
    1749            final TypeVariable<?> typeVar = entry.getKey();
    1750            final Type type = entry.getValue();
    1751
    1752            for (final Type bound : getImplicitBounds(typeVar)) {
    1753                if (!isAssignable(type, substituteTypeVariables(bound, typeVariableMap),
    1754                        typeVariableMap)) {
    1755                    return false;
    1756                }
    1757            }
    1758        }
    1759        return true;
    1760    }
    1761
    1762    /**
    1763     * Formats a {@link TypeVariable} as a {@link String}.
    1764     *
    1765     * @param typeVariable {@code TypeVariable} to format
    1766     * @return String
    1767     * @since 3.2
    1768     */
    1769    private static String typeVariableToString(final TypeVariable<?> typeVariable) {
    1770        final StringBuilder buf = new StringBuilder(typeVariable.getName());
    1771        final Type[] bounds = typeVariable.getBounds();
    1772        if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) {
    1773            buf.append(" extends ");
    1774            appendAllTo(buf, " & ", typeVariable.getBounds());
    1775        }
    1776        return buf.toString();
    1777    }
    1778
    1779    /**
    1780     * Unrolls variables in a type bounds array.
    1781     *
    1782     * @param typeArguments assignments {@link Map}
    1783     * @param bounds in which to expand variables
    1784     * @return {@code bounds} with any variables reassigned
    1785     * @since 3.2
    1786     */
    1787    private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
    1788        Type[] result = bounds;
    1789        int i = 0;
    1790        for (; i < result.length; i++) {
    1791            final Type unrolled = unrollVariables(typeArguments, result[i]);
    1792            if (unrolled == null) {
    1793                result = ArrayUtils.remove(result, i--);
    1794            } else {
    1795                result[i] = unrolled;
    1796            }
    1797        }
    1798        return result;
    1799    }
    1800
    1801    /**
    1802     * Look up {@code var} in {@code typeVarAssigns} <em>transitively</em>,
    1803     * i.e. keep looking until the value found is <em>not</em> a type variable.
    1804     *
    1805     * @param typeVariable the type variable to look up
    1806     * @param typeVarAssigns the map used for the look up
    1807     * @return Type or {@code null} if some variable was not in the map
    1808     * @since 3.2
    1809     */
    1810    private static Type unrollVariableAssignments(TypeVariable<?> typeVariable,
    1811        final Map<TypeVariable<?>, Type> typeVarAssigns) {
    1812        Type result;
    1813        do {
    1814            result = typeVarAssigns.get(typeVariable);
    1815            if (result instanceof TypeVariable<?> && !result.equals(typeVariable)) {
    1816                typeVariable = (TypeVariable<?>) result;
    1817                continue;
    1818            }
    1819            break;
    1820        } while (true);
    1821        return result;
    1822    }
    1823
    1824    /**
    1825     * Gets a type representing {@code type} with variable assignments "unrolled."
    1826     *
    1827     * @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)}
    1828     * @param type the type to unroll variable assignments for
    1829     * @return Type
    1830     * @since 3.2
    1831     */
    1832    public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
    1833        if (typeArguments == null) {
    1834            typeArguments = Collections.emptyMap();
    1835        }
    1836        if (containsTypeVariables(type)) {
    1837            if (type instanceof TypeVariable<?>) {
    1838                return unrollVariables(typeArguments, typeArguments.get(type));
    1839            }
    1840            if (type instanceof ParameterizedType) {
    1841                final ParameterizedType p = (ParameterizedType) type;
    1842                final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
    1843                if (p.getOwnerType() == null) {
    1844                    parameterizedTypeArguments = typeArguments;
    1845                } else {
    1846                    parameterizedTypeArguments = new HashMap<>(typeArguments);
    1847                    parameterizedTypeArguments.putAll(getTypeArguments(p));
    1848                }
    1849                final Type[] args = p.getActualTypeArguments();
    1850                for (int i = 0; i < args.length; i++) {
    1851                    final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
    1852                    if (unrolled != null) {
    1853                        args[i] = unrolled;
    1854                    }
    1855                }
    1856                return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
    1857            }
    1858            if (type instanceof WildcardType) {
    1859                final WildcardType wild = (WildcardType) type;
    1860                return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
    1861                    .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
    1862            }
    1863        }
    1864        return type;
    1865    }
    1866
    1867    /**
    1868     * Gets a {@link WildcardTypeBuilder}.
    1869     *
    1870     * @return {@link WildcardTypeBuilder}
    1871     * @since 3.2
    1872     */
    1873    public static WildcardTypeBuilder wildcardType() {
    1874        return new WildcardTypeBuilder();
    1875    }
    1876
    1877    /**
    1878     * Formats a {@link WildcardType} as a {@link String}.
    1879     *
    1880     * @param wildcardType {@code WildcardType} to format
    1881     * @return String
    1882     * @since 3.2
    1883     */
    1884    private static String wildcardTypeToString(final WildcardType wildcardType) {
    1885        final StringBuilder buf = new StringBuilder().append('?');
    1886        final Type[] lowerBounds = wildcardType.getLowerBounds();
    1887        final Type[] upperBounds = wildcardType.getUpperBounds();
    1888        if (lowerBounds.length > 1 || lowerBounds.length == 1 && lowerBounds[0] != null) {
    1889            appendAllTo(buf.append(" super "), " & ", lowerBounds);
    1890        } else if (upperBounds.length > 1 || upperBounds.length == 1 && !Object.class.equals(upperBounds[0])) {
    1891            appendAllTo(buf.append(" extends "), " & ", upperBounds);
    1892        }
    1893        return buf.toString();
    1894    }
    1895
    1896    /**
    1897     * Wraps the specified {@link Class} in a {@link Typed} wrapper.
    1898     *
    1899     * @param <T> generic type
    1900     * @param type to wrap
    1901     * @return Typed&lt;T&gt;
    1902     * @since 3.2
    1903     */
    1904    public static <T> Typed<T> wrap(final Class<T> type) {
    1905        return wrap((Type) type);
    1906    }
    1907
    1908    /**
    1909     * Wraps the specified {@link Type} in a {@link Typed} wrapper.
    1910     *
    1911     * @param <T> inferred generic type
    1912     * @param type to wrap
    1913     * @return Typed&lt;T&gt;
    1914     * @since 3.2
    1915     */
    1916    public static <T> Typed<T> wrap(final Type type) {
    1917        return () -> type;
    1918    }
    1919
    1920    /**
    1921     * {@code TypeUtils} instances should NOT be constructed in standard
    1922     * programming. Instead, the class should be used as
    1923     * {@code TypeUtils.isAssignable(cls, toClass)}.
    1924     * <p>
    1925     * This constructor is public to permit tools that require a JavaBean instance
    1926     * to operate.
    1927     * </p>
    1928     */
    1929    public TypeUtils() {
    1930    }
    1931
    1932}