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