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 }