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