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