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