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