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