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