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