1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
46
47
48
49 public class TypeUtils {
50
51
52
53
54 private static final class GenericArrayTypeImpl implements GenericArrayType {
55 private final Type componentType;
56
57
58
59
60
61
62 private GenericArrayTypeImpl(final Type componentType) {
63 this.componentType = componentType;
64 }
65
66
67
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
76
77 @Override
78 public Type getGenericComponentType() {
79 return componentType;
80 }
81
82
83
84
85 @Override
86 public int hashCode() {
87 int result = 67 << 4;
88 result |= componentType.hashCode();
89 return result;
90 }
91
92
93
94
95 @Override
96 public String toString() {
97 return TypeUtils.toString(this);
98 }
99 }
100
101
102
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
111
112
113
114
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
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
132
133 @Override
134 public Type[] getActualTypeArguments() {
135 return typeArguments.clone();
136 }
137
138
139
140
141 @Override
142 public Type getOwnerType() {
143 return useOwner;
144 }
145
146
147
148
149 @Override
150 public Type getRawType() {
151 return raw;
152 }
153
154
155
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
170
171 @Override
172 public String toString() {
173 return TypeUtils.toString(this);
174 }
175 }
176
177
178
179
180
181
182 public static class WildcardTypeBuilder implements Builder<WildcardType> {
183 private Type[] upperBounds;
184
185 private Type[] lowerBounds;
186
187
188
189
190 private WildcardTypeBuilder() {
191 }
192
193
194
195
196 @Override
197 public WildcardType build() {
198 return new WildcardTypeImpl(upperBounds, lowerBounds);
199 }
200
201
202
203
204
205
206
207 public WildcardTypeBuilder withLowerBounds(final Type... bounds) {
208 this.lowerBounds = bounds;
209 return this;
210 }
211
212
213
214
215
216
217
218 public WildcardTypeBuilder withUpperBounds(final Type... bounds) {
219 this.upperBounds = bounds;
220 return this;
221 }
222 }
223
224
225
226
227 private static final class WildcardTypeImpl implements WildcardType {
228 private final Type[] upperBounds;
229 private final Type[] lowerBounds;
230
231
232
233
234
235
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
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
252
253 @Override
254 public Type[] getLowerBounds() {
255 return lowerBounds.clone();
256 }
257
258
259
260
261 @Override
262 public Type[] getUpperBounds() {
263 return upperBounds.clone();
264 }
265
266
267
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
280
281 @Override
282 public String toString() {
283 return TypeUtils.toString(this);
284 }
285 }
286
287
288
289
290
291 private static final AppendableJoiner<Type> AMP_JOINER = AppendableJoiner.<Type>builder()
292 .setDelimiter(" & ")
293 .setElementAppender((a, e) -> a.append(toString(e)))
294 .get();
295
296
297
298
299
300
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
306
307
308
309
310
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
318
319
320
321
322
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 (final Type type : argumentTypes) {
332
333 GT_JOINER.join(builder, Objects.toString(type));
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
343
344
345
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, (Object[]) cls.getTypeParameters());
362 }
363 return buf.toString();
364 }
365
366
367
368
369
370
371
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
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
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
428 if (!isAssignable(cls, superClass)) {
429 return null;
430 }
431 if (cls.equals(superClass)) {
432 return getTypeArguments(superParameterizedType, superClass, null);
433 }
434
435 final Type midType = getClosestParentType(cls, superClass);
436
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
443
444 final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superParameterizedType);
445
446 mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
447 return typeVarAssigns;
448 }
449
450
451
452
453
454
455
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
463
464
465
466
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
480
481
482
483
484
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
504
505
506
507
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
523
524
525
526
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
539
540
541
542
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
568
569
570
571
572
573 public static GenericArrayType genericArrayType(final Type componentType) {
574 return new GenericArrayTypeImpl(Objects.requireNonNull(componentType, "componentType"));
575 }
576
577
578
579
580
581
582
583 private static String genericArrayTypeToString(final GenericArrayType genericArrayType) {
584 return String.format("%s[]", toString(genericArrayType.getGenericComponentType()));
585 }
586
587
588
589
590
591
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
606
607
608
609
610
611 private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
612
613 if (superClass.isInterface()) {
614
615 final Type[] interfaceTypes = cls.getGenericInterfaces();
616
617 Type genericInterface = null;
618
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
629
630 if (isAssignable(midClass, superClass) && isAssignable(genericInterface, (Type) midClass)) {
631 genericInterface = midType;
632 }
633 }
634
635 if (genericInterface != null) {
636 return genericInterface;
637 }
638 }
639
640
641 return cls.getGenericSuperclass();
642 }
643
644
645
646
647
648
649
650
651
652 public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
653 return normalizeUpperToObject(Objects.requireNonNull(typeVariable, "typeVariable").getBounds());
654 }
655
656
657
658
659
660
661
662
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
672
673
674
675
676
677
678 public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
679 return normalizeUpperToObject(Objects.requireNonNull(wildcardType, "wildcardType").getUpperBounds());
680 }
681
682
683
684
685
686
687
688
689 private static Class<?> getRawType(final ParameterizedType parameterizedType) {
690 final Type rawType = parameterizedType.getRawType();
691
692
693
694
695
696 if (!(rawType instanceof Class<?>)) {
697 throw new IllegalStateException("Type of rawType: " + rawType);
698 }
699 return (Class<?>) rawType;
700 }
701
702
703
704
705
706
707
708
709
710
711 public static Class<?> getRawType(final Type type, final Type assigningType) {
712 if (type instanceof Class<?>) {
713
714 return (Class<?>) type;
715 }
716 if (type instanceof ParameterizedType) {
717
718 return getRawType((ParameterizedType) type);
719 }
720 if (type instanceof TypeVariable<?>) {
721 if (assigningType == null) {
722 return null;
723 }
724
725 final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
726
727
728 if (!(genericDeclaration instanceof Class<?>)) {
729 return null;
730 }
731
732
733 final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType, (Class<?>) genericDeclaration);
734
735
736 if (typeVarAssigns == null) {
737 return null;
738 }
739
740 final Type typeArgument = typeVarAssigns.get(type);
741 if (typeArgument == null) {
742 return null;
743 }
744
745 return getRawType(typeArgument, assigningType);
746 }
747 if (type instanceof GenericArrayType) {
748
749 final Class<?> rawComponentType = getRawType(((GenericArrayType) type).getGenericComponentType(), assigningType);
750
751 return rawComponentType != null ? Array.newInstance(rawComponentType, 0).getClass() : null;
752 }
753
754 if (type instanceof WildcardType) {
755 return null;
756 }
757 throw new IllegalArgumentException("unknown type: " + type);
758 }
759
760
761
762
763
764
765
766
767
768 private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass, final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
769
770 if (!isAssignable(cls, toClass)) {
771 return null;
772 }
773
774 if (cls.isPrimitive()) {
775
776 if (toClass.isPrimitive()) {
777
778
779 return new HashMap<>();
780 }
781
782 cls = ClassUtils.primitiveToWrapper(cls);
783 }
784
785 final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>() : new HashMap<>(subtypeVarAssigns);
786
787 if (toClass.equals(cls)) {
788 return typeVarAssigns;
789 }
790
791 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
792 }
793
794
795
796
797
798
799
800
801 public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
802 return getTypeArguments(type, getRawType(type), null);
803 }
804
805
806
807
808
809
810
811
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
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
824 final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
825 typeVarAssigns = getTypeArguments(parameterizedOwnerType, getRawType(parameterizedOwnerType), subtypeVarAssigns);
826 } else {
827
828 typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>() : new HashMap<>(subtypeVarAssigns);
829 }
830
831 final Type[] typeArgs = parameterizedType.getActualTypeArguments();
832
833 final TypeVariable<?>[] typeParams = cls.getTypeParameters();
834
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
841 return typeVarAssigns;
842 }
843
844 final Type parentType = getClosestParentType(cls, toClass);
845 if (parentType instanceof ParameterizedType) {
846 final ParameterizedType parameterizedParentType = (ParameterizedType) parentType;
847 final Type[] parentTypeArgs = parameterizedParentType.getActualTypeArguments().clone();
848 for (int i = 0; i < parentTypeArgs.length; i++) {
849 final Type unrolled = unrollVariables(typeVarAssigns, parentTypeArgs[i]);
850 if (unrolled != null) {
851 parentTypeArgs[i] = unrolled;
852 }
853 }
854 return getTypeArguments(parameterizeWithOwner(parameterizedParentType.getOwnerType(), (Class<?>) parameterizedParentType.getRawType(), parentTypeArgs), toClass, typeVarAssigns);
855 }
856 return getTypeArguments(parentType, toClass, typeVarAssigns);
857 }
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884 public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
885 return getTypeArguments(type, toClass, null);
886 }
887
888
889
890
891
892
893
894
895
896 private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass, final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
897 if (type instanceof Class<?>) {
898 return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
899 }
900 if (type instanceof ParameterizedType) {
901 return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
902 }
903 if (type instanceof GenericArrayType) {
904 return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass.isArray() ? toClass.getComponentType() : toClass,
905 subtypeVarAssigns);
906 }
907
908
909 if (type instanceof WildcardType) {
910 for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
911
912 if (isAssignable(bound, toClass)) {
913 return getTypeArguments(bound, toClass, subtypeVarAssigns);
914 }
915 }
916 return null;
917 }
918 if (type instanceof TypeVariable<?>) {
919 for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
920
921 if (isAssignable(bound, toClass)) {
922 return getTypeArguments(bound, toClass, subtypeVarAssigns);
923 }
924 }
925 return null;
926 }
927 throw new IllegalStateException("found an unhandled type: " + type);
928 }
929
930
931
932
933
934
935
936 public static boolean isArrayType(final Type type) {
937 return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
938 }
939
940
941
942
943
944
945
946
947 private static boolean isAssignable(final Type type, final Class<?> toClass) {
948 if (type == null) {
949
950 return toClass == null || !toClass.isPrimitive();
951 }
952
953
954 if (toClass == null) {
955 return false;
956 }
957
958 if (toClass.equals(type)) {
959 return true;
960 }
961 if (type instanceof Class<?>) {
962
963 return ClassUtils.isAssignable((Class<?>) type, toClass);
964 }
965 if (type instanceof ParameterizedType) {
966
967 return isAssignable(getRawType((ParameterizedType) type), toClass);
968 }
969
970 if (type instanceof TypeVariable<?>) {
971
972
973 for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
974 if (isAssignable(bound, toClass)) {
975 return true;
976 }
977 }
978 return false;
979 }
980
981
982 if (type instanceof GenericArrayType) {
983 return toClass.equals(Object.class)
984 || toClass.isArray() && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass.getComponentType());
985 }
986
987
988 if (type instanceof WildcardType) {
989 return false;
990 }
991 throw new IllegalStateException("found an unhandled type: " + type);
992 }
993
994
995
996
997
998
999
1000
1001
1002 private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1003 if (type == null) {
1004 return true;
1005 }
1006
1007
1008 if (toGenericArrayType == null) {
1009 return false;
1010 }
1011
1012 if (toGenericArrayType.equals(type)) {
1013 return true;
1014 }
1015 final Type toComponentType = toGenericArrayType.getGenericComponentType();
1016 if (type instanceof Class<?>) {
1017 final Class<?> cls = (Class<?>) type;
1018
1019 return cls.isArray() && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
1020 }
1021 if (type instanceof GenericArrayType) {
1022
1023 return isAssignable(((GenericArrayType) type).getGenericComponentType(), toComponentType, typeVarAssigns);
1024 }
1025 if (type instanceof WildcardType) {
1026
1027 for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
1028 if (isAssignable(bound, toGenericArrayType)) {
1029 return true;
1030 }
1031 }
1032 return false;
1033 }
1034 if (type instanceof TypeVariable<?>) {
1035
1036
1037 for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
1038 if (isAssignable(bound, toGenericArrayType)) {
1039 return true;
1040 }
1041 }
1042 return false;
1043 }
1044 if (type instanceof ParameterizedType) {
1045
1046
1047
1048 return false;
1049 }
1050 throw new IllegalStateException("found an unhandled type: " + type);
1051 }
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061 private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1062 if (type == null) {
1063 return true;
1064 }
1065
1066
1067 if (toParameterizedType == null) {
1068 return false;
1069 }
1070
1071 if (type instanceof GenericArrayType) {
1072 return false;
1073 }
1074
1075 if (toParameterizedType.equals(type)) {
1076 return true;
1077 }
1078
1079 final Class<?> toClass = getRawType(toParameterizedType);
1080
1081
1082 final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
1083
1084 if (fromTypeVarAssigns == null) {
1085 return false;
1086 }
1087
1088
1089
1090 if (fromTypeVarAssigns.isEmpty()) {
1091 return true;
1092 }
1093
1094 final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType, toClass, typeVarAssigns);
1095
1096 if (toClass.equals(Class.class)) {
1097 final TypeVariable<?>[] typeParams = toClass.getTypeParameters();
1098 if (typeParams.length > 0) {
1099 final Type toTypeArg = unrollVariableAssignments(typeParams[0], toTypeVarAssigns);
1100 final Type fromTypeArg = unrollVariableAssignments(typeParams[0], fromTypeVarAssigns);
1101 if (toTypeArg != null && (fromTypeArg == null || !toTypeArg.equals(fromTypeArg))) {
1102 return false;
1103 }
1104 }
1105 }
1106
1107 for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
1108 final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
1109 final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
1110 if (toTypeArg == null && fromTypeArg instanceof Class) {
1111 continue;
1112 }
1113
1114
1115
1116 if (fromTypeArg != null && toTypeArg != null && !toTypeArg.equals(fromTypeArg)
1117 && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg, typeVarAssigns))) {
1118 return false;
1119 }
1120 }
1121 return true;
1122 }
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132 public static boolean isAssignable(final Type type, final Type toType) {
1133 return isAssignable(type, toType, null);
1134 }
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144 private static boolean isAssignable(final Type type, final Type toType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1145 if (toType == null || toType instanceof Class<?>) {
1146 return isAssignable(type, (Class<?>) toType);
1147 }
1148 if (toType instanceof ParameterizedType) {
1149 return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
1150 }
1151 if (toType instanceof GenericArrayType) {
1152 return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
1153 }
1154 if (toType instanceof WildcardType) {
1155 return isAssignable(type, (WildcardType) toType, typeVarAssigns);
1156 }
1157 if (toType instanceof TypeVariable<?>) {
1158 return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
1159 }
1160 throw new IllegalStateException("found an unhandled type: " + toType);
1161 }
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171 private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1172 if (type == null) {
1173 return true;
1174 }
1175
1176
1177 if (toTypeVariable == null) {
1178 return false;
1179 }
1180
1181 if (toTypeVariable.equals(type)) {
1182 return true;
1183 }
1184 if (type instanceof TypeVariable<?>) {
1185
1186
1187
1188 final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
1189 for (final Type bound : bounds) {
1190 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
1191 return true;
1192 }
1193 }
1194 }
1195 if (type instanceof Class<?> || type instanceof ParameterizedType || type instanceof GenericArrayType || type instanceof WildcardType) {
1196 return false;
1197 }
1198 throw new IllegalStateException("found an unhandled type: " + type);
1199 }
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209 private static boolean isAssignable(final Type type, final WildcardType toWildcardType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1210 if (type == null) {
1211 return true;
1212 }
1213
1214
1215 if (toWildcardType == null) {
1216 return false;
1217 }
1218
1219 if (toWildcardType.equals(type)) {
1220 return true;
1221 }
1222 final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
1223 final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
1224 if (type instanceof WildcardType) {
1225 final WildcardType wildcardType = (WildcardType) type;
1226 final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
1227 final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
1228 for (Type toBound : toUpperBounds) {
1229
1230
1231 toBound = substituteTypeVariables(toBound, typeVarAssigns);
1232
1233
1234
1235 for (final Type bound : upperBounds) {
1236 if (!isAssignable(bound, toBound, typeVarAssigns)) {
1237 return false;
1238 }
1239 }
1240 }
1241 for (Type toBound : toLowerBounds) {
1242
1243
1244 toBound = substituteTypeVariables(toBound, typeVarAssigns);
1245
1246
1247
1248 for (final Type bound : lowerBounds) {
1249 if (!isAssignable(toBound, bound, typeVarAssigns)) {
1250 return false;
1251 }
1252 }
1253 }
1254 return true;
1255 }
1256 for (final Type toBound : toUpperBounds) {
1257
1258
1259 if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns), typeVarAssigns)) {
1260 return false;
1261 }
1262 }
1263 for (final Type toBound : toLowerBounds) {
1264
1265
1266 if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type, typeVarAssigns)) {
1267 return false;
1268 }
1269 }
1270 return true;
1271 }
1272
1273
1274
1275
1276
1277
1278
1279
1280 private static boolean isCyclical(final Class<?> cls) {
1281 for (final TypeVariable<?> typeParameter : cls.getTypeParameters()) {
1282 for (final Type bound : typeParameter.getBounds()) {
1283 if (bound.getTypeName().contains(cls.getName())) {
1284 return true;
1285 }
1286 }
1287 }
1288 return false;
1289 }
1290
1291
1292
1293
1294
1295
1296
1297
1298 public static boolean isInstance(final Object value, final Type type) {
1299 if (type == null) {
1300 return false;
1301 }
1302 return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive() : isAssignable(value.getClass(), type, null);
1303 }
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313 private static <T> void mapTypeVariablesToArguments(final Class<T> cls, final ParameterizedType parameterizedType,
1314 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1315
1316 final Type ownerType = parameterizedType.getOwnerType();
1317 if (ownerType instanceof ParameterizedType) {
1318
1319 mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
1320 }
1321
1322
1323
1324
1325 final Type[] typeArgs = parameterizedType.getActualTypeArguments();
1326
1327
1328 final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
1329
1330 final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls.getTypeParameters());
1331 for (int i = 0; i < typeArgs.length; i++) {
1332 final TypeVariable<?> typeVar = typeVars[i];
1333 final Type typeArg = typeArgs[i];
1334
1335 if (typeVarList.contains(typeArg)
1336
1337
1338 && typeVarAssigns.containsKey(typeVar)) {
1339
1340 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
1341 }
1342 }
1343 }
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369 public static Type[] normalizeUpperBounds(final Type[] bounds) {
1370 Objects.requireNonNull(bounds, "bounds");
1371
1372 if (bounds.length < 2) {
1373 return bounds;
1374 }
1375 final Set<Type> types = new HashSet<>(bounds.length);
1376 for (final Type type1 : bounds) {
1377 boolean subtypeFound = false;
1378 for (final Type type2 : bounds) {
1379 if (type1 != type2 && isAssignable(type2, type1, null)) {
1380 subtypeFound = true;
1381 break;
1382 }
1383 }
1384 if (!subtypeFound) {
1385 types.add(type1);
1386 }
1387 }
1388 return types.toArray(ArrayUtils.EMPTY_TYPE_ARRAY);
1389 }
1390
1391
1392
1393
1394
1395
1396
1397
1398 private static Type[] normalizeUpperToObject(final Type[] bounds) {
1399 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
1400 }
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411 public static final ParameterizedType parameterize(final Class<?> rawClass, final Map<TypeVariable<?>, Type> typeVariableMap) {
1412 Objects.requireNonNull(rawClass, "rawClass");
1413 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1414 return parameterizeWithOwner(null, rawClass, extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
1415 }
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426 public static final ParameterizedType parameterize(final Class<?> rawClass, final Type... typeArguments) {
1427 return parameterizeWithOwner(null, rawClass, typeArguments);
1428 }
1429
1430
1431
1432
1433
1434
1435
1436 private static String parameterizedTypeToString(final ParameterizedType parameterizedType) {
1437 final StringBuilder builder = new StringBuilder();
1438 final Type useOwner = parameterizedType.getOwnerType();
1439 final Class<?> raw = (Class<?>) parameterizedType.getRawType();
1440 if (useOwner == null) {
1441 builder.append(raw.getName());
1442 } else {
1443 if (useOwner instanceof Class<?>) {
1444 builder.append(((Class<?>) useOwner).getName());
1445 } else {
1446 builder.append(useOwner);
1447 }
1448 builder.append('.').append(raw.getSimpleName());
1449 }
1450 final int[] recursiveTypeIndexes = findRecursiveTypes(parameterizedType);
1451 if (recursiveTypeIndexes.length > 0) {
1452 appendRecursiveTypes(builder, recursiveTypeIndexes, parameterizedType.getActualTypeArguments());
1453 } else {
1454 GT_JOINER.join(builder, (Object[]) parameterizedType.getActualTypeArguments());
1455 }
1456 return builder.toString();
1457 }
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469 public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass, final Map<TypeVariable<?>, Type> typeVariableMap) {
1470 Objects.requireNonNull(rawClass, "rawClass");
1471 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1472 return parameterizeWithOwner(owner, rawClass, extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
1473 }
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485 public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass, final Type... typeArguments) {
1486 Objects.requireNonNull(rawClass, "rawClass");
1487 final Type useOwner;
1488 if (rawClass.getEnclosingClass() == null) {
1489 Validate.isTrue(owner == null, "no owner allowed for top-level %s", rawClass);
1490 useOwner = null;
1491 } else if (owner == null) {
1492 useOwner = rawClass.getEnclosingClass();
1493 } else {
1494 Validate.isTrue(isAssignable(owner, rawClass.getEnclosingClass()), "%s is invalid owner type for parameterized %s", owner, rawClass);
1495 useOwner = owner;
1496 }
1497 Validate.noNullElements(typeArguments, "null type argument at index %s");
1498 Validate.isTrue(rawClass.getTypeParameters().length == typeArguments.length, "invalid number of type parameters specified: expected %d, got %d",
1499 rawClass.getTypeParameters().length, typeArguments.length);
1500 return new ParameterizedTypeImpl(rawClass, useOwner, typeArguments);
1501 }
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511 private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1512 if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
1513 final Type replacementType = typeVarAssigns.get(type);
1514 if (replacementType == null) {
1515 throw new IllegalArgumentException("missing assignment type for type variable " + type);
1516 }
1517 return replacementType;
1518 }
1519 return type;
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530 public static String toLongString(final TypeVariable<?> typeVariable) {
1531 Objects.requireNonNull(typeVariable, "typeVariable");
1532 final StringBuilder buf = new StringBuilder();
1533 final GenericDeclaration d = typeVariable.getGenericDeclaration();
1534 if (d instanceof Class<?>) {
1535 Class<?> c = (Class<?>) d;
1536 while (true) {
1537 if (c.getEnclosingClass() == null) {
1538 buf.insert(0, c.getName());
1539 break;
1540 }
1541 buf.insert(0, c.getSimpleName()).insert(0, '.');
1542 c = c.getEnclosingClass();
1543 }
1544 } else if (d instanceof Type) {
1545 buf.append(toString((Type) d));
1546 } else {
1547 buf.append(d);
1548 }
1549 return buf.append(':').append(typeVariableToString(typeVariable)).toString();
1550 }
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560 public static String toString(final Type type) {
1561 Objects.requireNonNull(type, "type");
1562 if (type instanceof Class<?>) {
1563 return classToString((Class<?>) type);
1564 }
1565 if (type instanceof ParameterizedType) {
1566 return parameterizedTypeToString((ParameterizedType) type);
1567 }
1568 if (type instanceof WildcardType) {
1569 return wildcardTypeToString((WildcardType) type);
1570 }
1571 if (type instanceof TypeVariable<?>) {
1572 return typeVariableToString((TypeVariable<?>) type);
1573 }
1574 if (type instanceof GenericArrayType) {
1575 return genericArrayTypeToString((GenericArrayType) type);
1576 }
1577 throw new IllegalArgumentException(ObjectUtils.identityToString(type));
1578 }
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589 public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVariableMap) {
1590 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1591
1592
1593 for (final Map.Entry<TypeVariable<?>, Type> entry : typeVariableMap.entrySet()) {
1594 final TypeVariable<?> typeVar = entry.getKey();
1595 final Type type = entry.getValue();
1596 for (final Type bound : getImplicitBounds(typeVar)) {
1597 if (!isAssignable(type, substituteTypeVariables(bound, typeVariableMap), typeVariableMap)) {
1598 return false;
1599 }
1600 }
1601 }
1602 return true;
1603 }
1604
1605
1606
1607
1608
1609
1610
1611 private static String typeVariableToString(final TypeVariable<?> typeVariable) {
1612 final StringBuilder builder = new StringBuilder(typeVariable.getName());
1613 final Type[] bounds = typeVariable.getBounds();
1614 if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) {
1615
1616
1617
1618 final Type bound = bounds[0];
1619 boolean append = true;
1620 if (bound instanceof ParameterizedType) {
1621 final Type rawType = ((ParameterizedType) bound).getRawType();
1622 if (rawType instanceof Class && ((Class<?>) rawType).isInterface()) {
1623
1624 append = false;
1625 }
1626 }
1627 if (append) {
1628 builder.append(" extends ");
1629 AMP_JOINER.join(builder, bounds);
1630 }
1631 }
1632 return builder.toString();
1633 }
1634
1635
1636
1637
1638
1639
1640
1641
1642 private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
1643 Type[] result = bounds;
1644 int i = 0;
1645 for (; i < result.length; i++) {
1646 final Type unrolled = unrollVariables(typeArguments, result[i]);
1647 if (unrolled == null) {
1648 result = ArrayUtils.remove(result, i--);
1649 } else {
1650 result[i] = unrolled;
1651 }
1652 }
1653 return result;
1654 }
1655
1656
1657
1658
1659
1660
1661
1662
1663 private static Type unrollVariableAssignments(TypeVariable<?> typeVariable, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1664 Type result;
1665 do {
1666 result = typeVarAssigns.get(typeVariable);
1667 if (!(result instanceof TypeVariable<?>) || result.equals(typeVariable)) {
1668 break;
1669 }
1670 typeVariable = (TypeVariable<?>) result;
1671 } while (true);
1672 return result;
1673 }
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683 public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
1684 if (typeArguments == null) {
1685 typeArguments = Collections.emptyMap();
1686 }
1687 return unrollVariables(typeArguments, type, new HashSet<>());
1688 }
1689
1690 private static Type unrollVariables(final Map<TypeVariable<?>, Type> typeArguments, final Type type, final Set<TypeVariable<?>> visited) {
1691 if (containsTypeVariables(type)) {
1692 if (type instanceof TypeVariable<?>) {
1693 final TypeVariable<?> var = (TypeVariable<?>) type;
1694 if (!visited.add(var)) {
1695 return var;
1696 }
1697 return unrollVariables(typeArguments, typeArguments.get(type), visited);
1698 }
1699 if (type instanceof ParameterizedType) {
1700 final ParameterizedType p = (ParameterizedType) type;
1701 final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
1702 if (p.getOwnerType() == null) {
1703 parameterizedTypeArguments = typeArguments;
1704 } else {
1705 parameterizedTypeArguments = new HashMap<>(typeArguments);
1706 parameterizedTypeArguments.putAll(getTypeArguments(p));
1707 }
1708 final Type[] args = p.getActualTypeArguments().clone();
1709 for (int i = 0; i < args.length; i++) {
1710 final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i], visited);
1711 if (unrolled != null) {
1712 args[i] = unrolled;
1713 }
1714 }
1715 return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
1716 }
1717 if (type instanceof WildcardType) {
1718 final WildcardType wild = (WildcardType) type;
1719 return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
1720 .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
1721 }
1722 }
1723 return type;
1724 }
1725
1726
1727
1728
1729
1730
1731
1732 public static WildcardTypeBuilder wildcardType() {
1733 return new WildcardTypeBuilder();
1734 }
1735
1736
1737
1738
1739
1740
1741
1742 private static String wildcardTypeToString(final WildcardType wildcardType) {
1743 final StringBuilder builder = new StringBuilder().append('?');
1744 final Type[] lowerBounds = wildcardType.getLowerBounds();
1745 final Type[] upperBounds = wildcardType.getUpperBounds();
1746 if (lowerBounds.length > 1 || lowerBounds.length == 1 && lowerBounds[0] != null) {
1747 AMP_JOINER.join(builder.append(" super "), lowerBounds);
1748 } else if (upperBounds.length > 1 || upperBounds.length == 1 && !Object.class.equals(upperBounds[0])) {
1749 AMP_JOINER.join(builder.append(" extends "), upperBounds);
1750 }
1751 return builder.toString();
1752 }
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762 public static <T> Typed<T> wrap(final Class<T> type) {
1763 return wrap((Type) type);
1764 }
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774 public static <T> Typed<T> wrap(final Type type) {
1775 return () -> type;
1776 }
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787 @Deprecated
1788 public TypeUtils() {
1789
1790 }
1791
1792 }