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