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