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