001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.lang3.reflect;
018
019 import java.lang.reflect.Array;
020 import java.lang.reflect.GenericArrayType;
021 import java.lang.reflect.ParameterizedType;
022 import java.lang.reflect.Type;
023 import java.lang.reflect.TypeVariable;
024 import java.lang.reflect.WildcardType;
025 import java.util.Arrays;
026 import java.util.HashMap;
027 import java.util.HashSet;
028 import java.util.List;
029 import java.util.Map;
030 import java.util.Set;
031
032 import org.apache.commons.lang3.ClassUtils;
033
034 /**
035 * <p> Utility methods focusing on type inspection, particularly with regard to
036 * generics. </p>
037 *
038 * @since 3.0
039 * @version $Id: TypeUtils.java 1144929 2011-07-10 18:26:16Z ggregory $
040 */
041 public class TypeUtils {
042
043 /**
044 * <p> TypeUtils instances should NOT be constructed in standard
045 * programming. Instead, the class should be used as
046 * <code>TypeUtils.isAssignable(cls, toClass)</code>. </p> <p> This
047 * constructor is public to permit tools that require a JavaBean instance to
048 * operate. </p>
049 */
050 public TypeUtils() {
051 super();
052 }
053
054 /**
055 * <p> Checks if the subject type may be implicitly cast to the target type
056 * following the Java generics rules. If both types are {@link Class}
057 * objects, the method returns the result of
058 * {@link ClassUtils#isAssignable(Class, Class)}. </p>
059 *
060 * @param type the subject type to be assigned to the target type
061 * @param toType the target type
062 * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
063 */
064 public static boolean isAssignable(Type type, Type toType) {
065 return isAssignable(type, toType, null);
066 }
067
068 /**
069 * <p> Checks if the subject type may be implicitly cast to the target type
070 * following the Java generics rules. </p>
071 *
072 * @param type the subject type to be assigned to the target type
073 * @param toType the target type
074 * @param typeVarAssigns optional map of type variable assignments
075 * @return <code>true</code> if <code>type</code> is assignable to <code>toType</code>.
076 */
077 private static boolean isAssignable(Type type, Type toType,
078 Map<TypeVariable<?>, Type> typeVarAssigns) {
079 if (toType == null || toType instanceof Class<?>) {
080 return isAssignable(type, (Class<?>) toType);
081 }
082
083 if (toType instanceof ParameterizedType) {
084 return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
085 }
086
087 if (toType instanceof GenericArrayType) {
088 return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
089 }
090
091 if (toType instanceof WildcardType) {
092 return isAssignable(type, (WildcardType) toType, typeVarAssigns);
093 }
094
095 // *
096 if (toType instanceof TypeVariable<?>) {
097 return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
098 }
099 // */
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(Type type, 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 (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(Type type, ParameterizedType toParameterizedType,
180 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 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 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 Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
216 toClass, typeVarAssigns);
217
218 // now to check each type argument
219 for (Map.Entry<TypeVariable<?>, Type> entry : toTypeVarAssigns.entrySet()) {
220 Type toTypeArg = entry.getValue();
221 Type fromTypeArg = fromTypeVarAssigns.get(entry.getKey());
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 /**
238 * <p> Checks if the subject type may be implicitly cast to the target
239 * generic array type following the Java generics rules. </p>
240 *
241 * @param type the subject type to be assigned to the target type
242 * @param toGenericArrayType the target generic array type
243 * @param typeVarAssigns a map with type variables
244 * @return true if <code>type</code> is assignable to
245 * <code>toGenericArrayType</code>.
246 */
247 private static boolean isAssignable(Type type, GenericArrayType toGenericArrayType,
248 Map<TypeVariable<?>, Type> typeVarAssigns) {
249 if (type == null) {
250 return true;
251 }
252
253 // only a null type can be assigned to null type which
254 // would have cause the previous to return true
255 if (toGenericArrayType == null) {
256 return false;
257 }
258
259 // all types are assignable to themselves
260 if (toGenericArrayType.equals(type)) {
261 return true;
262 }
263
264 Type toComponentType = toGenericArrayType.getGenericComponentType();
265
266 if (type instanceof Class<?>) {
267 Class<?> cls = (Class<?>) type;
268
269 // compare the component types
270 return cls.isArray()
271 && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
272 }
273
274 if (type instanceof GenericArrayType) {
275 // compare the component types
276 return isAssignable(((GenericArrayType) type).getGenericComponentType(),
277 toComponentType, typeVarAssigns);
278 }
279
280 if (type instanceof WildcardType) {
281 // so long as one of the upper bounds is assignable, it's good
282 for (Type bound : getImplicitUpperBounds((WildcardType) type)) {
283 if (isAssignable(bound, toGenericArrayType)) {
284 return true;
285 }
286 }
287
288 return false;
289 }
290
291 if (type instanceof TypeVariable<?>) {
292 // probably should remove the following logic and just return false.
293 // type variables cannot specify arrays as bounds.
294 for (Type bound : getImplicitBounds((TypeVariable<?>) type)) {
295 if (isAssignable(bound, toGenericArrayType)) {
296 return true;
297 }
298 }
299
300 return false;
301 }
302
303 if (type instanceof ParameterizedType) {
304 // the raw type of a parameterized type is never an array or
305 // generic array, otherwise the declaration would look like this:
306 // Collection[]< ? extends String > collection;
307 return false;
308 }
309
310 throw new IllegalStateException("found an unhandled type: " + type);
311 }
312
313 /**
314 * <p> Checks if the subject type may be implicitly cast to the target
315 * wildcard type following the Java generics rules. </p>
316 *
317 * @param type the subject type to be assigned to the target type
318 * @param toWildcardType the target wildcard type
319 * @param typeVarAssigns a map with type variables
320 * @return true if <code>type</code> is assignable to
321 * <code>toWildcardType</code>.
322 */
323 private static boolean isAssignable(Type type, WildcardType toWildcardType,
324 Map<TypeVariable<?>, Type> typeVarAssigns) {
325 if (type == null) {
326 return true;
327 }
328
329 // only a null type can be assigned to null type which
330 // would have cause the previous to return true
331 if (toWildcardType == null) {
332 return false;
333 }
334
335 // all types are assignable to themselves
336 if (toWildcardType.equals(type)) {
337 return true;
338 }
339
340 Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
341 Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
342
343 if (type instanceof WildcardType) {
344 WildcardType wildcardType = (WildcardType) type;
345 Type[] upperBounds = getImplicitUpperBounds(wildcardType);
346 Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
347
348 for (Type toBound : toUpperBounds) {
349 // if there are assignments for unresolved type variables,
350 // now's the time to substitute them.
351 toBound = substituteTypeVariables(toBound, typeVarAssigns);
352
353 // each upper bound of the subject type has to be assignable to
354 // each
355 // upper bound of the target type
356 for (Type bound : upperBounds) {
357 if (!isAssignable(bound, toBound, typeVarAssigns)) {
358 return false;
359 }
360 }
361 }
362
363 for (Type toBound : toLowerBounds) {
364 // if there are assignments for unresolved type variables,
365 // now's the time to substitute them.
366 toBound = substituteTypeVariables(toBound, typeVarAssigns);
367
368 // each lower bound of the target type has to be assignable to
369 // each
370 // lower bound of the subject type
371 for (Type bound : lowerBounds) {
372 if (!isAssignable(toBound, bound, typeVarAssigns)) {
373 return false;
374 }
375 }
376 }
377
378 return true;
379 }
380
381 for (Type toBound : toUpperBounds) {
382 // if there are assignments for unresolved type variables,
383 // now's the time to substitute them.
384 if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
385 typeVarAssigns)) {
386 return false;
387 }
388 }
389
390 for (Type toBound : toLowerBounds) {
391 // if there are assignments for unresolved type variables,
392 // now's the time to substitute them.
393 if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
394 typeVarAssigns)) {
395 return false;
396 }
397 }
398
399 return true;
400 }
401
402 /**
403 * <p> Checks if the subject type may be implicitly cast to the target type
404 * variable following the Java generics rules. </p>
405 *
406 * @param type the subject type to be assigned to the target type
407 * @param toTypeVariable the target type variable
408 * @param typeVarAssigns a map with type variables
409 * @return true if <code>type</code> is assignable to
410 * <code>toTypeVariable</code>.
411 */
412 private static boolean isAssignable(Type type, TypeVariable<?> toTypeVariable,
413 Map<TypeVariable<?>, Type> typeVarAssigns) {
414 if (type == null) {
415 return true;
416 }
417
418 // only a null type can be assigned to null type which
419 // would have cause the previous to return true
420 if (toTypeVariable == null) {
421 return false;
422 }
423
424 // all types are assignable to themselves
425 if (toTypeVariable.equals(type)) {
426 return true;
427 }
428
429 if (type instanceof TypeVariable<?>) {
430 // a type variable is assignable to another type variable, if
431 // and only if the former is the latter, extends the latter, or
432 // is otherwise a descendant of the latter.
433 Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
434
435 for (Type bound : bounds) {
436 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
437 return true;
438 }
439 }
440 }
441
442 if (type instanceof Class<?> || type instanceof ParameterizedType
443 || type instanceof GenericArrayType || type instanceof WildcardType) {
444 return false;
445 }
446
447 throw new IllegalStateException("found an unhandled type: " + type);
448 }
449
450 /**
451 * <p> </p>
452 *
453 * @param type the type to be replaced
454 * @param typeVarAssigns the map with type variables
455 * @return the replaced type
456 * @throws IllegalArgumentException if the type cannot be substituted
457 */
458 private static Type substituteTypeVariables(Type type, Map<TypeVariable<?>, Type> typeVarAssigns) {
459 if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
460 Type replacementType = typeVarAssigns.get(type);
461
462 if (replacementType == null) {
463 throw new IllegalArgumentException("missing assignment type for type variable "
464 + type);
465 }
466
467 return replacementType;
468 }
469
470 return type;
471 }
472
473 /**
474 * <p> Retrieves all the type arguments for this parameterized type
475 * including owner hierarchy arguments such as <code>
476 * Outer<K,V>.Inner<T>.DeepInner<E></code> . The arguments are returned in a
477 * {@link Map} specifying the argument type for each {@link TypeVariable}.
478 * </p>
479 *
480 * @param type specifies the subject parameterized type from which to
481 * harvest the parameters.
482 * @return a map of the type arguments to their respective type variables.
483 */
484 public static Map<TypeVariable<?>, Type> getTypeArguments(ParameterizedType type) {
485 return getTypeArguments(type, getRawType(type), null);
486 }
487
488 /**
489 * <p> Gets the type arguments of a class/interface based on a subtype. For
490 * instance, this method will determine that both of the parameters for the
491 * interface {@link Map} are {@link Object} for the subtype
492 * {@link java.util.Properties Properties} even though the subtype does not
493 * directly implement the <code>Map</code> interface. <p> </p> This method
494 * returns <code>null</code> if <code>type</code> is not assignable to
495 * <code>toClass</code>. It returns an empty map if none of the classes or
496 * interfaces in its inheritance hierarchy specify any type arguments. </p>
497 * <p> A side-effect of this method is that it also retrieves the type
498 * arguments for the classes and interfaces that are part of the hierarchy
499 * between <code>type</code> and <code>toClass</code>. So with the above
500 * example, this method will also determine that the type arguments for
501 * {@link java.util.Hashtable Hashtable} are also both <code>Object</code>.
502 * In cases where the interface specified by <code>toClass</code> is
503 * (indirectly) implemented more than once (e.g. where <code>toClass</code>
504 * specifies the interface {@link java.lang.Iterable Iterable} and
505 * <code>type</code> specifies a parameterized type that implements both
506 * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
507 * this method will look at the inheritance hierarchy of only one of the
508 * implementations/subclasses; the first interface encountered that isn't a
509 * subinterface to one of the others in the <code>type</code> to
510 * <code>toClass</code> hierarchy. </p>
511 *
512 * @param type the type from which to determine the type parameters of
513 * <code>toClass</code>
514 * @param toClass the class whose type parameters are to be determined based
515 * on the subtype <code>type</code>
516 * @return a map of the type assignments for the type variables in each type
517 * in the inheritance hierarchy from <code>type</code> to
518 * <code>toClass</code> inclusive.
519 */
520 public static Map<TypeVariable<?>, Type> getTypeArguments(Type type, Class<?> toClass) {
521 return getTypeArguments(type, toClass, null);
522 }
523
524 /**
525 * <p> Return a map of the type arguments of <code>type</code> in the context of <code>toClass</code>. </p>
526 *
527 * @param type the type in question
528 * @param toClass the class
529 * @param subtypeVarAssigns a map with type variables
530 * @return the map with type arguments
531 */
532 private static Map<TypeVariable<?>, Type> getTypeArguments(Type type, Class<?> toClass,
533 Map<TypeVariable<?>, Type> subtypeVarAssigns) {
534 if (type instanceof Class<?>) {
535 return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
536 }
537
538 if (type instanceof ParameterizedType) {
539 return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
540 }
541
542 if (type instanceof GenericArrayType) {
543 return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
544 .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
545 }
546
547 // since wildcard types are not assignable to classes, should this just
548 // return null?
549 if (type instanceof WildcardType) {
550 for (Type bound : getImplicitUpperBounds((WildcardType) type)) {
551 // find the first bound that is assignable to the target class
552 if (isAssignable(bound, toClass)) {
553 return getTypeArguments(bound, toClass, subtypeVarAssigns);
554 }
555 }
556
557 return null;
558 }
559
560 // *
561 if (type instanceof TypeVariable<?>) {
562 for (Type bound : getImplicitBounds((TypeVariable<?>) type)) {
563 // find the first bound that is assignable to the target class
564 if (isAssignable(bound, toClass)) {
565 return getTypeArguments(bound, toClass, subtypeVarAssigns);
566 }
567 }
568
569 return null;
570 }
571 // */
572
573 throw new IllegalStateException("found an unhandled type: " + type);
574 }
575
576 /**
577 * <p> Return a map of the type arguments of a parameterized type in the context of <code>toClass</code>. </p>
578 *
579 * @param parameterizedType the parameterized type
580 * @param toClass the class
581 * @param subtypeVarAssigns a map with type variables
582 * @return the map with type arguments
583 */
584 private static Map<TypeVariable<?>, Type> getTypeArguments(
585 ParameterizedType parameterizedType, Class<?> toClass,
586 Map<TypeVariable<?>, Type> subtypeVarAssigns) {
587 Class<?> cls = getRawType(parameterizedType);
588
589 // make sure they're assignable
590 if (!isAssignable(cls, toClass)) {
591 return null;
592 }
593
594 Type ownerType = parameterizedType.getOwnerType();
595 Map<TypeVariable<?>, Type> typeVarAssigns;
596
597 if (ownerType instanceof ParameterizedType) {
598 // get the owner type arguments first
599 ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
600 typeVarAssigns = getTypeArguments(parameterizedOwnerType,
601 getRawType(parameterizedOwnerType), subtypeVarAssigns);
602 } else {
603 // no owner, prep the type variable assignments map
604 typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
605 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
606 }
607
608 // get the subject parameterized type's arguments
609 Type[] typeArgs = parameterizedType.getActualTypeArguments();
610 // and get the corresponding type variables from the raw class
611 TypeVariable<?>[] typeParams = cls.getTypeParameters();
612
613 // map the arguments to their respective type variables
614 for (int i = 0; i < typeParams.length; i++) {
615 Type typeArg = typeArgs[i];
616 typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
617 .get(typeArg) : typeArg);
618 }
619
620 if (toClass.equals(cls)) {
621 // target class has been reached. Done.
622 return typeVarAssigns;
623 }
624
625 // walk the inheritance hierarchy until the target class is reached
626 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
627 }
628
629 /**
630 * <p> Return a map of the type arguments of a class in the context of <code>toClass</code>. </p>
631 *
632 * @param cls the class in question
633 * @param toClass the context class
634 * @param subtypeVarAssigns a map with type variables
635 * @return the map with type arguments
636 */
637 private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, Class<?> toClass,
638 Map<TypeVariable<?>, Type> subtypeVarAssigns) {
639 // make sure they're assignable
640 if (!isAssignable(cls, toClass)) {
641 return null;
642 }
643
644 // can't work with primitives
645 if (cls.isPrimitive()) {
646 // both classes are primitives?
647 if (toClass.isPrimitive()) {
648 // dealing with widening here. No type arguments to be
649 // harvested with these two types.
650 return new HashMap<TypeVariable<?>, Type>();
651 }
652
653 // work with wrapper the wrapper class instead of the primitive
654 cls = ClassUtils.primitiveToWrapper(cls);
655 }
656
657 // create a copy of the incoming map, or an empty one if it's null
658 HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<TypeVariable<?>, Type>()
659 : new HashMap<TypeVariable<?>, Type>(subtypeVarAssigns);
660
661 // no arguments for the parameters, or target class has been reached
662 if (cls.getTypeParameters().length > 0 || toClass.equals(cls)) {
663 return typeVarAssigns;
664 }
665
666 // walk the inheritance hierarchy until the target class is reached
667 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
668 }
669
670 /**
671 * <p> Tries to determine the type arguments of a class/interface based on a
672 * super parameterized type's type arguments. This method is the inverse of
673 * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
674 * type arguments based on a subtype. It is far more limited in determining
675 * the type arguments for the subject class's type variables in that it can
676 * only determine those parameters that map from the subject {@link Class}
677 * object to the supertype. </p> <p> Example: {@link java.util.TreeSet
678 * TreeSet} sets its parameter as the parameter for
679 * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
680 * parameter of {@link java.util.SortedSet}, which in turn sets the
681 * parameter of {@link Set}, which in turn sets the parameter of
682 * {@link java.util.Collection}, which in turn sets the parameter of
683 * {@link java.lang.Iterable}. Since <code>TreeSet</code>'s parameter maps
684 * (indirectly) to <code>Iterable</code>'s parameter, it will be able to
685 * determine that based on the super type <code>Iterable<? extends
686 * Map<Integer,? extends Collection<?>>></code>, the parameter of
687 * <code>TreeSet</code> is <code>? extends Map<Integer,? extends
688 * Collection<?>></code>. </p>
689 *
690 * @param cls the class whose type parameters are to be determined
691 * @param superType the super type from which <code>cls</code>'s type
692 * arguments are to be determined
693 * @return a map of the type assignments that could be determined for the
694 * type variables in each type in the inheritance hierarchy from
695 * <code>type</code> to <code>toClass</code> inclusive.
696 */
697 public static Map<TypeVariable<?>, Type> determineTypeArguments(Class<?> cls,
698 ParameterizedType superType) {
699 Class<?> superClass = getRawType(superType);
700
701 // compatibility check
702 if (!isAssignable(cls, superClass)) {
703 return null;
704 }
705
706 if (cls.equals(superClass)) {
707 return getTypeArguments(superType, superClass, null);
708 }
709
710 // get the next class in the inheritance hierarchy
711 Type midType = getClosestParentType(cls, superClass);
712
713 // can only be a class or a parameterized type
714 if (midType instanceof Class<?>) {
715 return determineTypeArguments((Class<?>) midType, superType);
716 }
717
718 ParameterizedType midParameterizedType = (ParameterizedType) midType;
719 Class<?> midClass = getRawType(midParameterizedType);
720 // get the type variables of the mid class that map to the type
721 // arguments of the super class
722 Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
723 // map the arguments of the mid type to the class type variables
724 mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
725
726 return typeVarAssigns;
727 }
728
729 /**
730 * <p>Performs a mapping of type variables.</p>
731 *
732 * @param <T> the generic type of the class in question
733 * @param cls the class in question
734 * @param parameterizedType the parameterized type
735 * @param typeVarAssigns the map to be filled
736 */
737 private static <T> void mapTypeVariablesToArguments(Class<T> cls,
738 ParameterizedType parameterizedType, Map<TypeVariable<?>, Type> typeVarAssigns) {
739 // capture the type variables from the owner type that have assignments
740 Type ownerType = parameterizedType.getOwnerType();
741
742 if (ownerType instanceof ParameterizedType) {
743 // recursion to make sure the owner's owner type gets processed
744 mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
745 }
746
747 // parameterizedType is a generic interface/class (or it's in the owner
748 // hierarchy of said interface/class) implemented/extended by the class
749 // cls. Find out which type variables of cls are type arguments of
750 // parameterizedType:
751 Type[] typeArgs = parameterizedType.getActualTypeArguments();
752
753 // of the cls's type variables that are arguments of parameterizedType,
754 // find out which ones can be determined from the super type's arguments
755 TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
756
757 // use List view of type parameters of cls so the contains() method can be used:
758 List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
759 .getTypeParameters());
760
761 for (int i = 0; i < typeArgs.length; i++) {
762 TypeVariable<?> typeVar = typeVars[i];
763 Type typeArg = typeArgs[i];
764
765 // argument of parameterizedType is a type variable of cls
766 if (typeVarList.contains(typeArg)
767 // type variable of parameterizedType has an assignment in
768 // the super type.
769 && typeVarAssigns.containsKey(typeVar)) {
770 // map the assignment to the cls's type variable
771 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
772 }
773 }
774 }
775
776 /**
777 * <p> Closest parent type? Closest to what? The closest parent type to the
778 * super class specified by <code>superClass</code>. </p>
779 *
780 * @param cls the class in question
781 * @param superClass the super class
782 * @return the closes parent type
783 */
784 private static Type getClosestParentType(Class<?> cls, Class<?> superClass) {
785 // only look at the interfaces if the super class is also an interface
786 if (superClass.isInterface()) {
787 // get the generic interfaces of the subject class
788 Type[] interfaceTypes = cls.getGenericInterfaces();
789 // will hold the best generic interface match found
790 Type genericInterface = null;
791
792 // find the interface closest to the super class
793 for (Type midType : interfaceTypes) {
794 Class<?> midClass = null;
795
796 if (midType instanceof ParameterizedType) {
797 midClass = getRawType((ParameterizedType) midType);
798 } else if (midType instanceof Class<?>) {
799 midClass = (Class<?>) midType;
800 } else {
801 throw new IllegalStateException("Unexpected generic"
802 + " interface type found: " + midType);
803 }
804
805 // check if this interface is further up the inheritance chain
806 // than the previously found match
807 if (isAssignable(midClass, superClass)
808 && isAssignable(genericInterface, (Type) midClass)) {
809 genericInterface = midType;
810 }
811 }
812
813 // found a match?
814 if (genericInterface != null) {
815 return genericInterface;
816 }
817 }
818
819 // none of the interfaces were descendants of the target class, so the
820 // super class has to be one, instead
821 return cls.getGenericSuperclass();
822 }
823
824 /**
825 * <p> Checks if the given value can be assigned to the target type
826 * following the Java generics rules. </p>
827 *
828 * @param value the value to be checked
829 * @param type the target type
830 * @return true of <code>value</code> is an instance of <code>type</code>.
831 */
832 public static boolean isInstance(Object value, Type type) {
833 if (type == null) {
834 return false;
835 }
836
837 return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
838 : isAssignable(value.getClass(), type, null);
839 }
840
841 /**
842 * <p> This method strips out the redundant upper bound types in type
843 * variable types and wildcard types (or it would with wildcard types if
844 * multiple upper bounds were allowed). </p> <p> Example: with the variable
845 * type declaration:
846 *
847 * <pre> <K extends java.util.Collection<String> &
848 * java.util.List<String>> </pre>
849 *
850 * since <code>List</code> is a subinterface of <code>Collection</code>,
851 * this method will return the bounds as if the declaration had been:
852 *
853 * <pre> <K extends java.util.List<String>> </pre>
854 *
855 * </p>
856 *
857 * @param bounds an array of types representing the upper bounds of either
858 * <code>WildcardType</code> or <code>TypeVariable</code>.
859 * @return an array containing the values from <code>bounds</code> minus the
860 * redundant types.
861 */
862 public static Type[] normalizeUpperBounds(Type[] bounds) {
863 // don't bother if there's only one (or none) type
864 if (bounds.length < 2) {
865 return bounds;
866 }
867
868 Set<Type> types = new HashSet<Type>(bounds.length);
869
870 for (Type type1 : bounds) {
871 boolean subtypeFound = false;
872
873 for (Type type2 : bounds) {
874 if (type1 != type2 && isAssignable(type2, type1, null)) {
875 subtypeFound = true;
876 break;
877 }
878 }
879
880 if (!subtypeFound) {
881 types.add(type1);
882 }
883 }
884
885 return types.toArray(new Type[types.size()]);
886 }
887
888 /**
889 * <p> Returns an array containing the sole type of {@link Object} if
890 * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
891 * returns the result of <code>TypeVariable.getBounds()</code> passed into
892 * {@link #normalizeUpperBounds}. </p>
893 *
894 * @param typeVariable the subject type variable
895 * @return a non-empty array containing the bounds of the type variable.
896 */
897 public static Type[] getImplicitBounds(TypeVariable<?> typeVariable) {
898 Type[] bounds = typeVariable.getBounds();
899
900 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
901 }
902
903 /**
904 * <p> Returns an array containing the sole value of {@link Object} if
905 * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
906 * it returns the result of <code>WildcardType.getUpperBounds()</code>
907 * passed into {@link #normalizeUpperBounds}. </p>
908 *
909 * @param wildcardType the subject wildcard type
910 * @return a non-empty array containing the upper bounds of the wildcard
911 * type.
912 */
913 public static Type[] getImplicitUpperBounds(WildcardType wildcardType) {
914 Type[] bounds = wildcardType.getUpperBounds();
915
916 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
917 }
918
919 /**
920 * <p> Returns an array containing a single value of <code>null</code> if
921 * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
922 * it returns the result of <code>WildcardType.getLowerBounds()</code>. </p>
923 *
924 * @param wildcardType the subject wildcard type
925 * @return a non-empty array containing the lower bounds of the wildcard
926 * type.
927 */
928 public static Type[] getImplicitLowerBounds(WildcardType wildcardType) {
929 Type[] bounds = wildcardType.getLowerBounds();
930
931 return bounds.length == 0 ? new Type[] { null } : bounds;
932 }
933
934 /**
935 * <p> Determines whether or not specified types satisfy the bounds of their
936 * mapped type variables. When a type parameter extends another (such as
937 * <code><T, S extends T></code>), uses another as a type parameter (such as
938 * <code><T, S extends Comparable<T></code>), or otherwise depends on
939 * another type variable to be specified, the dependencies must be included
940 * in <code>typeVarAssigns</code>. </p>
941 *
942 * @param typeVarAssigns specifies the potential types to be assigned to the
943 * type variables.
944 * @return whether or not the types can be assigned to their respective type
945 * variables.
946 */
947 public static boolean typesSatisfyVariables(Map<TypeVariable<?>, Type> typeVarAssigns) {
948 // all types must be assignable to all the bounds of the their mapped
949 // type variable.
950 for (Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
951 TypeVariable<?> typeVar = entry.getKey();
952 Type type = entry.getValue();
953
954 for (Type bound : getImplicitBounds(typeVar)) {
955 if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
956 typeVarAssigns)) {
957 return false;
958 }
959 }
960 }
961
962 return true;
963 }
964
965 /**
966 * <p> Transforms the passed in type to a {@code Class} object. Type-checking method of convenience. </p>
967 *
968 * @param parameterizedType the type to be converted
969 * @return the corresponding {@code Class} object
970 * @throws IllegalStateException if the conversion fails
971 */
972 private static Class<?> getRawType(ParameterizedType parameterizedType) {
973 Type rawType = parameterizedType.getRawType();
974
975 // check if raw type is a Class object
976 // not currently necessary, but since the return type is Type instead of
977 // Class, there's enough reason to believe that future versions of Java
978 // may return other Type implementations. And type-safety checking is
979 // rarely a bad idea.
980 if (!(rawType instanceof Class<?>)) {
981 throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
982 }
983
984 return (Class<?>) rawType;
985 }
986
987 /**
988 * <p> Get the raw type of a Java type, given its context. Primarily for use
989 * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
990 * not know the runtime type of <code>type</code>: if you know you have a
991 * {@link Class} instance, it is already raw; if you know you have a
992 * {@link ParameterizedType}, its raw type is only a method call away. </p>
993 *
994 * @param type to resolve
995 * @param assigningType type to be resolved against
996 * @return the resolved <code>Class</code> object or <code>null</code> if
997 * the type could not be resolved
998 */
999 public static Class<?> getRawType(Type type, Type assigningType) {
1000 if (type instanceof Class<?>) {
1001 // it is raw, no problem
1002 return (Class<?>) type;
1003 }
1004
1005 if (type instanceof ParameterizedType) {
1006 // simple enough to get the raw type of a ParameterizedType
1007 return getRawType((ParameterizedType) type);
1008 }
1009
1010 if (type instanceof TypeVariable<?>) {
1011 if (assigningType == null) {
1012 return null;
1013 }
1014
1015 // get the entity declaring this type variable
1016 Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
1017
1018 // can't get the raw type of a method- or constructor-declared type
1019 // variable
1020 if (!(genericDeclaration instanceof Class<?>)) {
1021 return null;
1022 }
1023
1024 // get the type arguments for the declaring class/interface based
1025 // on the enclosing type
1026 Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
1027 (Class<?>) genericDeclaration);
1028
1029 // enclosingType has to be a subclass (or subinterface) of the
1030 // declaring type
1031 if (typeVarAssigns == null) {
1032 return null;
1033 }
1034
1035 // get the argument assigned to this type variable
1036 Type typeArgument = typeVarAssigns.get(type);
1037
1038 if (typeArgument == null) {
1039 return null;
1040 }
1041
1042 // get the argument for this type variable
1043 return getRawType(typeArgument, assigningType);
1044 }
1045
1046 if (type instanceof GenericArrayType) {
1047 // get raw component type
1048 Class<?> rawComponentType = getRawType(((GenericArrayType) type)
1049 .getGenericComponentType(), assigningType);
1050
1051 // create array type from raw component type and return its class
1052 return Array.newInstance(rawComponentType, 0).getClass();
1053 }
1054
1055 // (hand-waving) this is not the method you're looking for
1056 if (type instanceof WildcardType) {
1057 return null;
1058 }
1059
1060 throw new IllegalArgumentException("unknown type: " + type);
1061 }
1062
1063 /**
1064 * Learn whether the specified type denotes an array type.
1065 * @param type the type to be checked
1066 * @return <code>true</code> if <code>type</code> is an array class or a {@link GenericArrayType}.
1067 */
1068 public static boolean isArrayType(Type type) {
1069 return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
1070 }
1071
1072 /**
1073 * Get the array component type of <code>type</code>.
1074 * @param type the type to be checked
1075 * @return component type or null if type is not an array type
1076 */
1077 public static Type getArrayComponentType(Type type) {
1078 if (type instanceof Class<?>) {
1079 Class<?> clazz = (Class<?>) type;
1080 return clazz.isArray() ? clazz.getComponentType() : null;
1081 }
1082 if (type instanceof GenericArrayType) {
1083 return ((GenericArrayType) type).getGenericComponentType();
1084 }
1085 return null;
1086 }
1087
1088 }