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