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> <K extends java.util.Collection<String> &
861 * java.util.List<String>> </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> <K extends java.util.List<String>> </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 }