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