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