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