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