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