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