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.ParameterizedType;
22  import java.lang.reflect.Type;
23  import java.lang.reflect.TypeVariable;
24  import java.lang.reflect.WildcardType;
25  import java.util.Arrays;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import org.apache.commons.lang3.ClassUtils;
33  
34  /**
35   * <p> Utility methods focusing on type inspection, particularly with regard to
36   * generics. </p>
37   *
38   * @since 3.0
39   * @version $Id: TypeUtils.java 1436770 2013-01-22 07:09:45Z ggregory $
40   */
41  public class TypeUtils {
42  
43      /**
44       * <p> TypeUtils instances should NOT be constructed in standard
45       * programming. Instead, the class should be used as
46       * <code>TypeUtils.isAssignable(cls, toClass)</code>. </p> <p> This
47       * constructor is public to permit tools that require a JavaBean instance to
48       * operate. </p>
49       */
50      public TypeUtils() {
51          super();
52      }
53  
54      /**
55       * <p> Checks if the subject type may be implicitly cast to the target type
56       * following the Java generics rules. If both types are {@link Class}
57       * objects, the method returns the result of
58       * {@link ClassUtils#isAssignable(Class, Class)}. </p>
59       *
60       * @param type the subject type to be assigned to the target type
61       * @param toType the target type
62       * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
63       */
64      public static boolean isAssignable(final Type type, final Type toType) {
65          return isAssignable(type, toType, null);
66      }
67  
68      /**
69       * <p> Checks if the subject type may be implicitly cast to the target type
70       * following the Java generics rules. </p>
71       *
72       * @param type the subject type to be assigned to the target type
73       * @param toType the target type
74       * @param typeVarAssigns optional map of type variable assignments
75       * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
76       */
77      private static boolean isAssignable(final Type type, final Type toType,
78              final Map<TypeVariable<?>, Type> typeVarAssigns) {
79          if (toType == null || toType instanceof Class<?>) {
80              return isAssignable(type, (Class<?>) toType);
81          }
82  
83          if (toType instanceof ParameterizedType) {
84              return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
85          }
86  
87          if (toType instanceof GenericArrayType) {
88              return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
89          }
90  
91          if (toType instanceof WildcardType) {
92              return isAssignable(type, (WildcardType) toType, typeVarAssigns);
93          }
94  
95          // *
96          if (toType instanceof TypeVariable<?>) {
97              return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
98          }
99          // */
100 
101         throw new IllegalStateException("found an unhandled type: " + toType);
102     }
103 
104     /**
105      * <p> Checks if the subject type may be implicitly cast to the target class
106      * following the Java generics rules. </p>
107      *
108      * @param type the subject type to be assigned to the target type
109      * @param toClass the target class
110      * @return true if <code>type</code> is assignable to <code>toClass</code>.
111      */
112     private static boolean isAssignable(final Type type, final Class<?> toClass) {
113         if (type == null) {
114             // consistency with ClassUtils.isAssignable() behavior
115             return toClass == null || !toClass.isPrimitive();
116         }
117 
118         // only a null type can be assigned to null type which
119         // would have cause the previous to return true
120         if (toClass == null) {
121             return false;
122         }
123 
124         // all types are assignable to themselves
125         if (toClass.equals(type)) {
126             return true;
127         }
128 
129         if (type instanceof Class<?>) {
130             // just comparing two classes
131             return ClassUtils.isAssignable((Class<?>) type, toClass);
132         }
133 
134         if (type instanceof ParameterizedType) {
135             // only have to compare the raw type to the class
136             return isAssignable(getRawType((ParameterizedType) type), toClass);
137         }
138 
139         // *
140         if (type instanceof TypeVariable<?>) {
141             // if any of the bounds are assignable to the class, then the
142             // type is assignable to the class.
143             for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
144                 if (isAssignable(bound, toClass)) {
145                     return true;
146                 }
147             }
148 
149             return false;
150         }
151 
152         // the only classes to which a generic array type can be assigned
153         // are class Object and array classes
154         if (type instanceof GenericArrayType) {
155             return toClass.equals(Object.class)
156                     || toClass.isArray()
157                     && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
158                             .getComponentType());
159         }
160 
161         // wildcard types are not assignable to a class (though one would think
162         // "? super Object" would be assignable to Object)
163         if (type instanceof WildcardType) {
164             return false;
165         }
166 
167         throw new IllegalStateException("found an unhandled type: " + type);
168     }
169 
170     /**
171      * <p> Checks if the subject type may be implicitly cast to the target
172      * parameterized type following the Java generics rules. </p>
173      *
174      * @param type the subject type to be assigned to the target type
175      * @param toParameterizedType the target parameterized type
176      * @param typeVarAssigns a map with type variables
177      * @return true if <code>type</code> is assignable to <code>toType</code>.
178      */
179     private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
180             final Map<TypeVariable<?>, Type> typeVarAssigns) {
181         if (type == null) {
182             return true;
183         }
184 
185         // only a null type can be assigned to null type which
186         // would have cause the previous to return true
187         if (toParameterizedType == null) {
188             return false;
189         }
190 
191         // all types are assignable to themselves
192         if (toParameterizedType.equals(type)) {
193             return true;
194         }
195 
196         // get the target type's raw type
197         final Class<?> toClass = getRawType(toParameterizedType);
198         // get the subject type's type arguments including owner type arguments
199         // and supertype arguments up to and including the target class.
200         final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
201 
202         // null means the two types are not compatible
203         if (fromTypeVarAssigns == null) {
204             return false;
205         }
206 
207         // compatible types, but there's no type arguments. this is equivalent
208         // to comparing Map< ?, ? > to Map, and raw types are always assignable
209         // to parameterized types.
210         if (fromTypeVarAssigns.isEmpty()) {
211             return true;
212         }
213 
214         // get the target type's type arguments including owner type arguments
215         final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
216                 toClass, typeVarAssigns);
217 
218         // now to check each type argument
219         for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
220             final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
221             final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
222 
223             // parameters must either be absent from the subject type, within
224             // the bounds of the wildcard type, or be an exact match to the
225             // parameters of the target type.
226             if (fromTypeArg != null
227                     && !toTypeArg.equals(fromTypeArg)
228                     && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
229                             typeVarAssigns))) {
230                 return false;
231             }
232         }
233 
234         return true;
235     }
236 
237     private static Type unrollVariableAssignments(TypeVariable<?> var, final Map<TypeVariable<?>, Type> typeVarAssigns) {
238         Type result;
239         do {
240             result = typeVarAssigns.get(var);
241             if (result instanceof TypeVariable<?> && !result.equals(var)) {
242                 var = (TypeVariable<?>) result;
243                 continue;
244             }
245             break;
246         } while (true);
247         return result;
248     }
249 
250     /**
251      * <p> Checks if the subject type may be implicitly cast to the target
252      * generic array type following the Java generics rules. </p>
253      *
254      * @param type the subject type to be assigned to the target type
255      * @param toGenericArrayType the target generic array type
256      * @param typeVarAssigns a map with type variables
257      * @return true if <code>type</code> is assignable to
258      * <code>toGenericArrayType</code>.
259      */
260     private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
261             final Map<TypeVariable<?>, Type> typeVarAssigns) {
262         if (type == null) {
263             return true;
264         }
265 
266         // only a null type can be assigned to null type which
267         // would have cause the previous to return true
268         if (toGenericArrayType == null) {
269             return false;
270         }
271 
272         // all types are assignable to themselves
273         if (toGenericArrayType.equals(type)) {
274             return true;
275         }
276 
277         final Type toComponentType = toGenericArrayType.getGenericComponentType();
278 
279         if (type instanceof Class<?>) {
280             final Class<?> cls = (Class<?>) type;
281 
282             // compare the component types
283             return cls.isArray()
284                     && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
285         }
286 
287         if (type instanceof GenericArrayType) {
288             // compare the component types
289             return isAssignable(((GenericArrayType) type).getGenericComponentType(),
290                     toComponentType, typeVarAssigns);
291         }
292 
293         if (type instanceof WildcardType) {
294             // so long as one of the upper bounds is assignable, it's good
295             for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
296                 if (isAssignable(bound, toGenericArrayType)) {
297                     return true;
298                 }
299             }
300 
301             return false;
302         }
303 
304         if (type instanceof TypeVariable<?>) {
305             // probably should remove the following logic and just return false.
306             // type variables cannot specify arrays as bounds.
307             for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
308                 if (isAssignable(bound, toGenericArrayType)) {
309                     return true;
310                 }
311             }
312 
313             return false;
314         }
315 
316         if (type instanceof ParameterizedType) {
317             // the raw type of a parameterized type is never an array or
318             // generic array, otherwise the declaration would look like this:
319             // Collection[]< ? extends String > collection;
320             return false;
321         }
322 
323         throw new IllegalStateException("found an unhandled type: " + type);
324     }
325 
326     /**
327      * <p> Checks if the subject type may be implicitly cast to the target
328      * wildcard type following the Java generics rules. </p>
329      *
330      * @param type the subject type to be assigned to the target type
331      * @param toWildcardType the target wildcard type
332      * @param typeVarAssigns a map with type variables
333      * @return true if <code>type</code> is assignable to
334      * <code>toWildcardType</code>.
335      */
336     private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
337             final Map<TypeVariable<?>, Type> typeVarAssigns) {
338         if (type == null) {
339             return true;
340         }
341 
342         // only a null type can be assigned to null type which
343         // would have cause the previous to return true
344         if (toWildcardType == null) {
345             return false;
346         }
347 
348         // all types are assignable to themselves
349         if (toWildcardType.equals(type)) {
350             return true;
351         }
352 
353         final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
354         final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
355 
356         if (type instanceof WildcardType) {
357             final WildcardType wildcardType = (WildcardType) type;
358             final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
359             final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
360 
361             for (Type toBound : toUpperBounds) {
362                 // if there are assignments for unresolved type variables,
363                 // now's the time to substitute them.
364                 toBound = substituteTypeVariables(toBound, typeVarAssigns);
365 
366                 // each upper bound of the subject type has to be assignable to
367                 // each
368                 // upper bound of the target type
369                 for (final Type bound : upperBounds) {
370                     if (!isAssignable(bound, toBound, typeVarAssigns)) {
371                         return false;
372                     }
373                 }
374             }
375 
376             for (Type toBound : toLowerBounds) {
377                 // if there are assignments for unresolved type variables,
378                 // now's the time to substitute them.
379                 toBound = substituteTypeVariables(toBound, typeVarAssigns);
380 
381                 // each lower bound of the target type has to be assignable to
382                 // each
383                 // lower bound of the subject type
384                 for (final Type bound : lowerBounds) {
385                     if (!isAssignable(toBound, bound, typeVarAssigns)) {
386                         return false;
387                     }
388                 }
389             }
390 
391             return true;
392         }
393 
394         for (final Type toBound : toUpperBounds) {
395             // if there are assignments for unresolved type variables,
396             // now's the time to substitute them.
397             if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
398                     typeVarAssigns)) {
399                 return false;
400             }
401         }
402 
403         for (final Type toBound : toLowerBounds) {
404             // if there are assignments for unresolved type variables,
405             // now's the time to substitute them.
406             if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
407                     typeVarAssigns)) {
408                 return false;
409             }
410         }
411 
412         return true;
413     }
414 
415     /**
416      * <p> Checks if the subject type may be implicitly cast to the target type
417      * variable following the Java generics rules. </p>
418      *
419      * @param type the subject type to be assigned to the target type
420      * @param toTypeVariable the target type variable
421      * @param typeVarAssigns a map with type variables
422      * @return true if <code>type</code> is assignable to
423      * <code>toTypeVariable</code>.
424      */
425     private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
426             final Map<TypeVariable<?>, Type> typeVarAssigns) {
427         if (type == null) {
428             return true;
429         }
430 
431         // only a null type can be assigned to null type which
432         // would have cause the previous to return true
433         if (toTypeVariable == null) {
434             return false;
435         }
436 
437         // all types are assignable to themselves
438         if (toTypeVariable.equals(type)) {
439             return true;
440         }
441 
442         if (type instanceof TypeVariable<?>) {
443             // a type variable is assignable to another type variable, if
444             // and only if the former is the latter, extends the latter, or
445             // is otherwise a descendant of the latter.
446             final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
447 
448             for (final Type bound : bounds) {
449                 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
450                     return true;
451                 }
452             }
453         }
454 
455         if (type instanceof Class<?> || type instanceof ParameterizedType
456                 || type instanceof GenericArrayType || type instanceof WildcardType) {
457             return false;
458         }
459 
460         throw new IllegalStateException("found an unhandled type: " + type);
461     }
462 
463     /**
464      * <p> </p>
465      *
466      * @param type the type to be replaced
467      * @param typeVarAssigns the map with type variables
468      * @return the replaced type
469      * @throws IllegalArgumentException if the type cannot be substituted
470      */
471     private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
472         if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
473             final Type replacementType = typeVarAssigns.get(type);
474 
475             if (replacementType == null) {
476                 throw new IllegalArgumentException("missing assignment type for type variable "
477                         + type);
478             }
479 
480             return replacementType;
481         }
482 
483         return type;
484     }
485 
486     /**
487      * <p> Retrieves all the type arguments for this parameterized type
488      * including owner hierarchy arguments such as <code>
489      * Outer<K,V>.Inner<T>.DeepInner<E></code> . The arguments are returned in a
490      * {@link Map} specifying the argument type for each {@link TypeVariable}.
491      * </p>
492      *
493      * @param type specifies the subject parameterized type from which to
494      * harvest the parameters.
495      * @return a map of the type arguments to their respective type variables.
496      */
497     public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
498         return getTypeArguments(type, getRawType(type), null);
499     }
500 
501     /**
502      * <p> Gets the type arguments of a class/interface based on a subtype. For
503      * instance, this method will determine that both of the parameters for the
504      * interface {@link Map} are {@link Object} for the subtype
505      * {@link java.util.Properties Properties} even though the subtype does not
506      * directly implement the <code>Map</code> interface. <p> </p> This method
507      * returns <code>null</code> if <code>type</code> is not assignable to
508      * <code>toClass</code>. It returns an empty map if none of the classes or
509      * interfaces in its inheritance hierarchy specify any type arguments. </p>
510      * <p> A side-effect of this method is that it also retrieves the type
511      * arguments for the classes and interfaces that are part of the hierarchy
512      * between <code>type</code> and <code>toClass</code>. So with the above
513      * example, this method will also determine that the type arguments for
514      * {@link java.util.Hashtable Hashtable} are also both <code>Object</code>.
515      * In cases where the interface specified by <code>toClass</code> is
516      * (indirectly) implemented more than once (e.g. where <code>toClass</code>
517      * specifies the interface {@link java.lang.Iterable Iterable} and
518      * <code>type</code> specifies a parameterized type that implements both
519      * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
520      * this method will look at the inheritance hierarchy of only one of the
521      * implementations/subclasses; the first interface encountered that isn't a
522      * subinterface to one of the others in the <code>type</code> to
523      * <code>toClass</code> hierarchy. </p>
524      *
525      * @param type the type from which to determine the type parameters of
526      * <code>toClass</code>
527      * @param toClass the class whose type parameters are to be determined based
528      * on the subtype <code>type</code>
529      * @return a map of the type assignments for the type variables in each type
530      * in the inheritance hierarchy from <code>type</code> to
531      * <code>toClass</code> inclusive.
532      */
533     public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
534         return getTypeArguments(type, toClass, null);
535     }
536 
537     /**
538      * <p> Return a map of the type arguments of <code>type</code> in the context of <code>toClass</code>. </p>
539      *
540      * @param type the type in question
541      * @param toClass the class
542      * @param subtypeVarAssigns a map with type variables
543      * @return the map with type arguments
544      */
545     private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass,
546             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
547         if (type instanceof Class<?>) {
548             return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
549         }
550 
551         if (type instanceof ParameterizedType) {
552             return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
553         }
554 
555         if (type instanceof GenericArrayType) {
556             return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
557                     .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
558         }
559 
560         // since wildcard types are not assignable to classes, should this just
561         // return null?
562         if (type instanceof WildcardType) {
563             for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
564                 // find the first bound that is assignable to the target class
565                 if (isAssignable(bound, toClass)) {
566                     return getTypeArguments(bound, toClass, subtypeVarAssigns);
567                 }
568             }
569 
570             return null;
571         }
572 
573         // *
574         if (type instanceof TypeVariable<?>) {
575             for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
576                 // find the first bound that is assignable to the target class
577                 if (isAssignable(bound, toClass)) {
578                     return getTypeArguments(bound, toClass, subtypeVarAssigns);
579                 }
580             }
581 
582             return null;
583         }
584         // */
585 
586         throw new IllegalStateException("found an unhandled type: " + type);
587     }
588 
589     /**
590      * <p> Return a map of the type arguments of a parameterized type in the context of <code>toClass</code>. </p>
591      *
592      * @param parameterizedType the parameterized type
593      * @param toClass the class
594      * @param subtypeVarAssigns a map with type variables
595      * @return the map with type arguments
596      */
597     private static Map<TypeVariable<?>, Type> getTypeArguments(
598             final ParameterizedType parameterizedType, final Class<?> toClass,
599             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
600         final Class<?> cls = getRawType(parameterizedType);
601 
602         // make sure they're assignable
603         if (!isAssignable(cls, toClass)) {
604             return null;
605         }
606 
607         final Type ownerType = parameterizedType.getOwnerType();
608         Map<TypeVariable<?>, Type> typeVarAssigns;
609 
610         if (ownerType instanceof ParameterizedType) {
611             // get the owner type arguments first
612             final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
613             typeVarAssigns = getTypeArguments(parameterizedOwnerType,
614                     getRawType(parameterizedOwnerType), subtypeVarAssigns);
615         } else {
616             // no owner, prep the type variable assignments map
617             typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
618                     : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
619         }
620 
621         // get the subject parameterized type's arguments
622         final Type[] typeArgs = parameterizedType.getActualTypeArguments();
623         // and get the corresponding type variables from the raw class
624         final TypeVariable<?>[] typeParams = cls.getTypeParameters();
625 
626         // map the arguments to their respective type variables
627         for (int i = 0; i < typeParams.length; i++) {
628             final Type typeArg = typeArgs[i];
629             typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
630                     .get(typeArg) : typeArg);
631         }
632 
633         if (toClass.equals(cls)) {
634             // target class has been reached. Done.
635             return typeVarAssigns;
636         }
637 
638         // walk the inheritance hierarchy until the target class is reached
639         return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
640     }
641 
642     /**
643      * <p> Return a map of the type arguments of a class in the context of <code>toClass</code>. </p>
644      *
645      * @param cls the class in question
646      * @param toClass the context class
647      * @param subtypeVarAssigns a map with type variables
648      * @return the map with type arguments
649      */
650     private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
651             final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
652         // make sure they're assignable
653         if (!isAssignable(cls, toClass)) {
654             return null;
655         }
656 
657         // can't work with primitives
658         if (cls.isPrimitive()) {
659             // both classes are primitives?
660             if (toClass.isPrimitive()) {
661                 // dealing with widening here. No type arguments to be
662                 // harvested with these two types.
663                 return new HashMap<TypeVariable<?>, Type>();
664             }
665 
666             // work with wrapper the wrapper class instead of the primitive
667             cls = ClassUtils.primitiveToWrapper(cls);
668         }
669 
670         // create a copy of the incoming map, or an empty one if it's null
671         final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
672                 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
673 
674         // has target class been reached?
675         if (toClass.equals(cls)) {
676             return typeVarAssigns;
677         }
678 
679         // walk the inheritance hierarchy until the target class is reached
680         return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
681     }
682 
683     /**
684      * <p> Tries to determine the type arguments of a class/interface based on a
685      * super parameterized type's type arguments. This method is the inverse of
686      * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
687      * type arguments based on a subtype. It is far more limited in determining
688      * the type arguments for the subject class's type variables in that it can
689      * only determine those parameters that map from the subject {@link Class}
690      * object to the supertype. </p> <p> Example: {@link java.util.TreeSet
691      * TreeSet} sets its parameter as the parameter for
692      * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
693      * parameter of {@link java.util.SortedSet}, which in turn sets the
694      * parameter of {@link Set}, which in turn sets the parameter of
695      * {@link java.util.Collection}, which in turn sets the parameter of
696      * {@link java.lang.Iterable}. Since <code>TreeSet</code>'s parameter maps
697      * (indirectly) to <code>Iterable</code>'s parameter, it will be able to
698      * determine that based on the super type <code>Iterable<? extends
699      * Map<Integer,? extends Collection<?>>></code>, the parameter of
700      * <code>TreeSet</code> is <code>? extends Map<Integer,? extends
701      * Collection<?>></code>. </p>
702      *
703      * @param cls the class whose type parameters are to be determined
704      * @param superType the super type from which <code>cls</code>'s type
705      * arguments are to be determined
706      * @return a map of the type assignments that could be determined for the
707      * type variables in each type in the inheritance hierarchy from
708      * <code>type</code> to <code>toClass</code> inclusive.
709      */
710     public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
711             final ParameterizedType superType) {
712         final Class<?> superClass = getRawType(superType);
713 
714         // compatibility check
715         if (!isAssignable(cls, superClass)) {
716             return null;
717         }
718 
719         if (cls.equals(superClass)) {
720             return getTypeArguments(superType, superClass, null);
721         }
722 
723         // get the next class in the inheritance hierarchy
724         final Type midType = getClosestParentType(cls, superClass);
725 
726         // can only be a class or a parameterized type
727         if (midType instanceof Class<?>) {
728             return determineTypeArguments((Class<?>) midType, superType);
729         }
730 
731         final ParameterizedType midParameterizedType = (ParameterizedType) midType;
732         final Class<?> midClass = getRawType(midParameterizedType);
733         // get the type variables of the mid class that map to the type
734         // arguments of the super class
735         final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
736         // map the arguments of the mid type to the class type variables
737         mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
738 
739         return typeVarAssigns;
740     }
741 
742     /**
743      * <p>Performs a mapping of type variables.</p>
744      *
745      * @param <T> the generic type of the class in question
746      * @param cls the class in question
747      * @param parameterizedType the parameterized type
748      * @param typeVarAssigns the map to be filled
749      */
750     private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
751             final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
752         // capture the type variables from the owner type that have assignments
753         final Type ownerType = parameterizedType.getOwnerType();
754 
755         if (ownerType instanceof ParameterizedType) {
756             // recursion to make sure the owner's owner type gets processed
757             mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
758         }
759 
760         // parameterizedType is a generic interface/class (or it's in the owner
761         // hierarchy of said interface/class) implemented/extended by the class
762         // cls. Find out which type variables of cls are type arguments of
763         // parameterizedType:
764         final Type[] typeArgs = parameterizedType.getActualTypeArguments();
765 
766         // of the cls's type variables that are arguments of parameterizedType,
767         // find out which ones can be determined from the super type's arguments
768         final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
769 
770         // use List view of type parameters of cls so the contains() method can be used:
771         final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
772                 .getTypeParameters());
773 
774         for (int i = 0; i < typeArgs.length; i++) {
775             final TypeVariable<?> typeVar = typeVars[i];
776             final Type typeArg = typeArgs[i];
777 
778             // argument of parameterizedType is a type variable of cls
779             if (typeVarList.contains(typeArg)
780             // type variable of parameterizedType has an assignment in
781                     // the super type.
782                     && typeVarAssigns.containsKey(typeVar)) {
783                 // map the assignment to the cls's type variable
784                 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
785             }
786         }
787     }
788 
789     /**
790      * <p> Closest parent type? Closest to what? The closest parent type to the
791      * super class specified by <code>superClass</code>. </p>
792      *
793      * @param cls the class in question
794      * @param superClass the super class
795      * @return the closes parent type
796      */
797     private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
798         // only look at the interfaces if the super class is also an interface
799         if (superClass.isInterface()) {
800             // get the generic interfaces of the subject class
801             final Type[] interfaceTypes = cls.getGenericInterfaces();
802             // will hold the best generic interface match found
803             Type genericInterface = null;
804 
805             // find the interface closest to the super class
806             for (final Type midType : interfaceTypes) {
807                 Class<?> midClass = null;
808 
809                 if (midType instanceof ParameterizedType) {
810                     midClass = getRawType((ParameterizedType) midType);
811                 } else if (midType instanceof Class<?>) {
812                     midClass = (Class<?>) midType;
813                 } else {
814                     throw new IllegalStateException("Unexpected generic"
815                             + " interface type found: " + midType);
816                 }
817 
818                 // check if this interface is further up the inheritance chain
819                 // than the previously found match
820                 if (isAssignable(midClass, superClass)
821                         && isAssignable(genericInterface, (Type) midClass)) {
822                     genericInterface = midType;
823                 }
824             }
825 
826             // found a match?
827             if (genericInterface != null) {
828                 return genericInterface;
829             }
830         }
831 
832         // none of the interfaces were descendants of the target class, so the
833         // super class has to be one, instead
834         return cls.getGenericSuperclass();
835     }
836 
837     /**
838      * <p> Checks if the given value can be assigned to the target type
839      * following the Java generics rules. </p>
840      *
841      * @param value the value to be checked
842      * @param type the target type
843      * @return true of <code>value</code> is an instance of <code>type</code>.
844      */
845     public static boolean isInstance(final Object value, final Type type) {
846         if (type == null) {
847             return false;
848         }
849 
850         return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
851                 : isAssignable(value.getClass(), type, null);
852     }
853 
854     /**
855      * <p> This method strips out the redundant upper bound types in type
856      * variable types and wildcard types (or it would with wildcard types if
857      * multiple upper bounds were allowed). </p> <p> Example: with the variable
858      * type declaration:
859      *
860      * <pre> &lt;K extends java.util.Collection&lt;String&gt; &amp;
861      * java.util.List&lt;String&gt;&gt; </pre>
862      *
863      * since <code>List</code> is a subinterface of <code>Collection</code>,
864      * this method will return the bounds as if the declaration had been:
865      *
866      * <pre> &lt;K extends java.util.List&lt;String&gt;&gt; </pre>
867      *
868      * </p>
869      *
870      * @param bounds an array of types representing the upper bounds of either
871      * <code>WildcardType</code> or <code>TypeVariable</code>.
872      * @return an array containing the values from <code>bounds</code> minus the
873      * redundant types.
874      */
875     public static Type[] normalizeUpperBounds(final Type[] bounds) {
876         // don't bother if there's only one (or none) type
877         if (bounds.length < 2) {
878             return bounds;
879         }
880 
881         final Set<Type> types = new HashSet<Type>(bounds.length);
882 
883         for (final Type type1 : bounds) {
884             boolean subtypeFound = false;
885 
886             for (final Type type2 : bounds) {
887                 if (type1 != type2 && isAssignable(type2, type1, null)) {
888                     subtypeFound = true;
889                     break;
890                 }
891             }
892 
893             if (!subtypeFound) {
894                 types.add(type1);
895             }
896         }
897 
898         return types.toArray(new Type[types.size()]);
899     }
900 
901     /**
902      * <p> Returns an array containing the sole type of {@link Object} if
903      * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
904      * returns the result of <code>TypeVariable.getBounds()</code> passed into
905      * {@link #normalizeUpperBounds}. </p>
906      *
907      * @param typeVariable the subject type variable
908      * @return a non-empty array containing the bounds of the type variable.
909      */
910     public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
911         final Type[] bounds = typeVariable.getBounds();
912 
913         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
914     }
915 
916     /**
917      * <p> Returns an array containing the sole value of {@link Object} if
918      * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
919      * it returns the result of <code>WildcardType.getUpperBounds()</code>
920      * passed into {@link #normalizeUpperBounds}. </p>
921      *
922      * @param wildcardType the subject wildcard type
923      * @return a non-empty array containing the upper bounds of the wildcard
924      * type.
925      */
926     public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
927         final Type[] bounds = wildcardType.getUpperBounds();
928 
929         return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
930     }
931 
932     /**
933      * <p> Returns an array containing a single value of <code>null</code> if
934      * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
935      * it returns the result of <code>WildcardType.getLowerBounds()</code>. </p>
936      *
937      * @param wildcardType the subject wildcard type
938      * @return a non-empty array containing the lower bounds of the wildcard
939      * type.
940      */
941     public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
942         final Type[] bounds = wildcardType.getLowerBounds();
943 
944         return bounds.length == 0 ? new Type[] { null } : bounds;
945     }
946 
947     /**
948      * <p> Determines whether or not specified types satisfy the bounds of their
949      * mapped type variables. When a type parameter extends another (such as
950      * <code><T, S extends T></code>), uses another as a type parameter (such as
951      * <code><T, S extends Comparable<T></code>), or otherwise depends on
952      * another type variable to be specified, the dependencies must be included
953      * in <code>typeVarAssigns</code>. </p>
954      *
955      * @param typeVarAssigns specifies the potential types to be assigned to the
956      * type variables.
957      * @return whether or not the types can be assigned to their respective type
958      * variables.
959      */
960     public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
961         // all types must be assignable to all the bounds of the their mapped
962         // type variable.
963         for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
964             final TypeVariable<?> typeVar = entry.getKey();
965             final Type type = entry.getValue();
966 
967             for (final Type bound : getImplicitBounds(typeVar)) {
968                 if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
969                         typeVarAssigns)) {
970                     return false;
971                 }
972             }
973         }
974 
975         return true;
976     }
977 
978     /**
979      * <p> Transforms the passed in type to a {@code Class} object. Type-checking method of convenience. </p>
980      *
981      * @param parameterizedType the type to be converted
982      * @return the corresponding {@code Class} object
983      * @throws IllegalStateException if the conversion fails
984      */
985     private static Class<?> getRawType(final ParameterizedType parameterizedType) {
986         final Type rawType = parameterizedType.getRawType();
987 
988         // check if raw type is a Class object
989         // not currently necessary, but since the return type is Type instead of
990         // Class, there's enough reason to believe that future versions of Java
991         // may return other Type implementations. And type-safety checking is
992         // rarely a bad idea.
993         if (!(rawType instanceof Class<?>)) {
994             throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
995         }
996 
997         return (Class<?>) rawType;
998     }
999 
1000     /**
1001      * <p> Get the raw type of a Java type, given its context. Primarily for use
1002      * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
1003      * not know the runtime type of <code>type</code>: if you know you have a
1004      * {@link Class} instance, it is already raw; if you know you have a
1005      * {@link ParameterizedType}, its raw type is only a method call away. </p>
1006      *
1007      * @param type to resolve
1008      * @param assigningType type to be resolved against
1009      * @return the resolved <code>Class</code> object or <code>null</code> if
1010      * the type could not be resolved
1011      */
1012     public static Class<?> getRawType(final Type type, final Type assigningType) {
1013         if (type instanceof Class<?>) {
1014             // it is raw, no problem
1015             return (Class<?>) type;
1016         }
1017 
1018         if (type instanceof ParameterizedType) {
1019             // simple enough to get the raw type of a ParameterizedType
1020             return getRawType((ParameterizedType) type);
1021         }
1022 
1023         if (type instanceof TypeVariable<?>) {
1024             if (assigningType == null) {
1025                 return null;
1026             }
1027 
1028             // get the entity declaring this type variable
1029             final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
1030 
1031             // can't get the raw type of a method- or constructor-declared type
1032             // variable
1033             if (!(genericDeclaration instanceof Class<?>)) {
1034                 return null;
1035             }
1036 
1037             // get the type arguments for the declaring class/interface based
1038             // on the enclosing type
1039             final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
1040                     (Class<?>) genericDeclaration);
1041 
1042             // enclosingType has to be a subclass (or subinterface) of the
1043             // declaring type
1044             if (typeVarAssigns == null) {
1045                 return null;
1046             }
1047 
1048             // get the argument assigned to this type variable
1049             final Type typeArgument = typeVarAssigns.get(type);
1050 
1051             if (typeArgument == null) {
1052                 return null;
1053             }
1054 
1055             // get the argument for this type variable
1056             return getRawType(typeArgument, assigningType);
1057         }
1058 
1059         if (type instanceof GenericArrayType) {
1060             // get raw component type
1061             final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
1062                     .getGenericComponentType(), assigningType);
1063 
1064             // create array type from raw component type and return its class
1065             return Array.newInstance(rawComponentType, 0).getClass();
1066         }
1067 
1068         // (hand-waving) this is not the method you're looking for
1069         if (type instanceof WildcardType) {
1070             return null;
1071         }
1072 
1073         throw new IllegalArgumentException("unknown type: " + type);
1074     }
1075 
1076     /**
1077      * Learn whether the specified type denotes an array type.
1078      * @param type the type to be checked
1079      * @return <code>true</code> if <code>type</code> is an array class or a {@link GenericArrayType}.
1080      */
1081     public static boolean isArrayType(final Type type) {
1082         return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
1083     }
1084 
1085     /**
1086      * Get the array component type of <code>type</code>.
1087      * @param type the type to be checked
1088      * @return component type or null if type is not an array type
1089      */
1090     public static Type getArrayComponentType(final Type type) {
1091         if (type instanceof Class<?>) {
1092             final Class<?> clazz = (Class<?>) type;
1093             return clazz.isArray() ? clazz.getComponentType() : null;
1094         }
1095         if (type instanceof GenericArrayType) {
1096             return ((GenericArrayType) type).getGenericComponentType();
1097         }
1098         return null;
1099     }
1100 
1101 }