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