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