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