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