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.ArrayUtils;
38 import org.apache.commons.lang3.ClassUtils;
39 import org.apache.commons.lang3.ObjectUtils;
40 import org.apache.commons.lang3.Validate;
41 import org.apache.commons.lang3.builder.Builder;
42
43
44
45
46
47
48
49 public class TypeUtils {
50
51
52
53
54
55 private static final class GenericArrayTypeImpl implements GenericArrayType {
56 private final Type componentType;
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
105 private static final class ParameterizedTypeImpl implements ParameterizedType {
106 private final Class<?> raw;
107 private final Type useOwner;
108 private final Type[] typeArguments;
109
110
111
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 public static class WildcardTypeBuilder implements Builder<WildcardType> {
182 private Type[] upperBounds;
183
184 private Type[] lowerBounds;
185
186
187
188 private WildcardTypeBuilder() {
189 }
190
191
192
193
194 @Override
195 public WildcardType build() {
196 return new WildcardTypeImpl(upperBounds, lowerBounds);
197 }
198
199
200
201
202
203
204 public WildcardTypeBuilder withLowerBounds(final Type... bounds) {
205 this.lowerBounds = bounds;
206 return this;
207 }
208
209
210
211
212
213
214 public WildcardTypeBuilder withUpperBounds(final Type... bounds) {
215 this.upperBounds = bounds;
216 return this;
217 }
218 }
219
220
221
222
223
224 private static final class WildcardTypeImpl implements WildcardType {
225 private final Type[] upperBounds;
226 private final Type[] lowerBounds;
227
228
229
230
231
232
233 private WildcardTypeImpl(final Type[] upperBounds, final Type[] lowerBounds) {
234 this.upperBounds = ObjectUtils.defaultIfNull(upperBounds, ArrayUtils.EMPTY_TYPE_ARRAY);
235 this.lowerBounds = ObjectUtils.defaultIfNull(lowerBounds, ArrayUtils.EMPTY_TYPE_ARRAY);
236 }
237
238
239
240
241 @Override
242 public boolean equals(final Object obj) {
243 return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj);
244 }
245
246
247
248
249 @Override
250 public Type[] getLowerBounds() {
251 return lowerBounds.clone();
252 }
253
254
255
256
257 @Override
258 public Type[] getUpperBounds() {
259 return upperBounds.clone();
260 }
261
262
263
264
265 @Override
266 public int hashCode() {
267 int result = 73 << 8;
268 result |= Arrays.hashCode(upperBounds);
269 result <<= 8;
270 result |= Arrays.hashCode(lowerBounds);
271 return result;
272 }
273
274
275
276
277 @Override
278 public String toString() {
279 return TypeUtils.toString(this);
280 }
281 }
282
283
284
285
286
287 public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build();
288
289
290
291
292
293
294
295
296
297
298 private static <T> StringBuilder appendAllTo(final StringBuilder builder, final String sep,
299 @SuppressWarnings("unchecked") final T... types) {
300 Validate.notEmpty(Validate.noNullElements(types));
301 if (types.length > 0) {
302 builder.append(toString(types[0]));
303 for (int i = 1; i < types.length; i++) {
304 builder.append(sep).append(toString(types[i]));
305 }
306 }
307 return builder;
308 }
309
310 private static void appendRecursiveTypes(final StringBuilder builder, final int[] recursiveTypeIndexes,
311 final Type[] argumentTypes) {
312 for (int i = 0; i < recursiveTypeIndexes.length; i++) {
313 appendAllTo(builder.append('<'), ", ", argumentTypes[i].toString()).append('>');
314 }
315
316 final Type[] argumentsFiltered = ArrayUtils.removeAll(argumentTypes, recursiveTypeIndexes);
317
318 if (argumentsFiltered.length > 0) {
319 appendAllTo(builder.append('<'), ", ", argumentsFiltered).append('>');
320 }
321 }
322
323
324
325
326
327
328
329
330 private static String classToString(final Class<?> cls) {
331 if (cls.isArray()) {
332 return toString(cls.getComponentType()) + "[]";
333 }
334
335 final StringBuilder buf = new StringBuilder();
336
337 if (cls.getEnclosingClass() != null) {
338 buf.append(classToString(cls.getEnclosingClass())).append('.').append(cls.getSimpleName());
339 } else {
340 buf.append(cls.getName());
341 }
342 if (cls.getTypeParameters().length > 0) {
343 buf.append('<');
344 appendAllTo(buf, ", ", cls.getTypeParameters());
345 buf.append('>');
346 }
347 return buf.toString();
348 }
349
350
351
352
353
354
355
356
357 public static boolean containsTypeVariables(final Type type) {
358 if (type instanceof TypeVariable<?>) {
359 return true;
360 }
361 if (type instanceof Class<?>) {
362 return ((Class<?>) type).getTypeParameters().length > 0;
363 }
364 if (type instanceof ParameterizedType) {
365 for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
366 if (containsTypeVariables(arg)) {
367 return true;
368 }
369 }
370 return false;
371 }
372 if (type instanceof WildcardType) {
373 final WildcardType wild = (WildcardType) type;
374 return containsTypeVariables(getImplicitLowerBounds(wild)[0])
375 || containsTypeVariables(getImplicitUpperBounds(wild)[0]);
376 }
377 if (type instanceof GenericArrayType) {
378 return containsTypeVariables(((GenericArrayType) type).getGenericComponentType());
379 }
380 return false;
381 }
382
383 private static boolean containsVariableTypeSameParametrizedTypeBound(final TypeVariable<?> typeVariable,
384 final ParameterizedType parameterizedType) {
385 return ArrayUtils.contains(typeVariable.getBounds(), parameterizedType);
386 }
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420 public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
421 final ParameterizedType superParameterizedType) {
422 Objects.requireNonNull(cls, "cls");
423 Objects.requireNonNull(superParameterizedType, "superParameterizedType");
424
425 final Class<?> superClass = getRawType(superParameterizedType);
426
427
428 if (!isAssignable(cls, superClass)) {
429 return null;
430 }
431
432 if (cls.equals(superClass)) {
433 return getTypeArguments(superParameterizedType, superClass, null);
434 }
435
436
437 final Type midType = getClosestParentType(cls, superClass);
438
439
440 if (midType instanceof Class<?>) {
441 return determineTypeArguments((Class<?>) midType, superParameterizedType);
442 }
443
444 final ParameterizedType midParameterizedType = (ParameterizedType) midType;
445 final Class<?> midClass = getRawType(midParameterizedType);
446
447
448 final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superParameterizedType);
449
450 mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
451
452 return typeVarAssigns;
453 }
454
455
456
457
458
459
460
461
462
463 private static boolean equals(final GenericArrayType genericArrayType, final Type type) {
464 return type instanceof GenericArrayType
465 && equals(genericArrayType.getGenericComponentType(), ((GenericArrayType) type).getGenericComponentType());
466 }
467
468
469
470
471
472
473
474
475
476 private static boolean equals(final ParameterizedType parameterizedType, final Type type) {
477 if (type instanceof ParameterizedType) {
478 final ParameterizedType other = (ParameterizedType) type;
479 if (equals(parameterizedType.getRawType(), other.getRawType())
480 && equals(parameterizedType.getOwnerType(), other.getOwnerType())) {
481 return equals(parameterizedType.getActualTypeArguments(), other.getActualTypeArguments());
482 }
483 }
484 return false;
485 }
486
487
488
489
490
491
492
493
494
495 public static boolean equals(final Type type1, final Type type2) {
496 if (Objects.equals(type1, type2)) {
497 return true;
498 }
499 if (type1 instanceof ParameterizedType) {
500 return equals((ParameterizedType) type1, type2);
501 }
502 if (type1 instanceof GenericArrayType) {
503 return equals((GenericArrayType) type1, type2);
504 }
505 if (type1 instanceof WildcardType) {
506 return equals((WildcardType) type1, type2);
507 }
508 return false;
509 }
510
511
512
513
514
515
516
517
518
519 private static boolean equals(final Type[] type1, final Type[] type2) {
520 if (type1.length == type2.length) {
521 for (int i = 0; i < type1.length; i++) {
522 if (!equals(type1[i], type2[i])) {
523 return false;
524 }
525 }
526 return true;
527 }
528 return false;
529 }
530
531
532
533
534
535
536
537
538
539 private static boolean equals(final WildcardType wildcardType, final Type type) {
540 if (type instanceof WildcardType) {
541 final WildcardType other = (WildcardType) type;
542 return equals(getImplicitLowerBounds(wildcardType), getImplicitLowerBounds(other))
543 && equals(getImplicitUpperBounds(wildcardType), getImplicitUpperBounds(other));
544 }
545 return false;
546 }
547
548
549
550
551
552
553
554
555 private static Type[] extractTypeArgumentsFrom(final Map<TypeVariable<?>, Type> mappings, final TypeVariable<?>[] variables) {
556 final Type[] result = new Type[variables.length];
557 int index = 0;
558 for (final TypeVariable<?> var : variables) {
559 Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var));
560 result[index++] = mappings.get(var);
561 }
562 return result;
563 }
564
565 private static int[] findRecursiveTypes(final ParameterizedType parameterizedType) {
566 final Type[] filteredArgumentTypes = Arrays.copyOf(parameterizedType.getActualTypeArguments(),
567 parameterizedType.getActualTypeArguments().length);
568 int[] indexesToRemove = {};
569 for (int i = 0; i < filteredArgumentTypes.length; i++) {
570 if (filteredArgumentTypes[i] instanceof TypeVariable<?> && containsVariableTypeSameParametrizedTypeBound(
571 (TypeVariable<?>) filteredArgumentTypes[i], parameterizedType)) {
572 indexesToRemove = ArrayUtils.add(indexesToRemove, i);
573 }
574 }
575 return indexesToRemove;
576 }
577
578
579
580
581
582
583
584
585
586 public static GenericArrayType genericArrayType(final Type componentType) {
587 return new GenericArrayTypeImpl(Objects.requireNonNull(componentType, "componentType"));
588 }
589
590
591
592
593
594
595
596
597 private static String genericArrayTypeToString(final GenericArrayType genericArrayType) {
598 return String.format("%s[]", toString(genericArrayType.getGenericComponentType()));
599 }
600
601
602
603
604
605
606
607 public static Type getArrayComponentType(final Type type) {
608 if (type instanceof Class<?>) {
609 final Class<?> cls = (Class<?>) type;
610 return cls.isArray() ? cls.getComponentType() : null;
611 }
612 if (type instanceof GenericArrayType) {
613 return ((GenericArrayType) type).getGenericComponentType();
614 }
615 return null;
616 }
617
618
619
620
621
622
623
624
625
626 private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
627
628 if (superClass.isInterface()) {
629
630 final Type[] interfaceTypes = cls.getGenericInterfaces();
631
632 Type genericInterface = null;
633
634
635 for (final Type midType : interfaceTypes) {
636 final Class<?> midClass;
637
638 if (midType instanceof ParameterizedType) {
639 midClass = getRawType((ParameterizedType) midType);
640 } else if (midType instanceof Class<?>) {
641 midClass = (Class<?>) midType;
642 } else {
643 throw new IllegalStateException("Unexpected generic"
644 + " interface type found: " + midType);
645 }
646
647
648
649 if (isAssignable(midClass, superClass)
650 && isAssignable(genericInterface, (Type) midClass)) {
651 genericInterface = midType;
652 }
653 }
654
655
656 if (genericInterface != null) {
657 return genericInterface;
658 }
659 }
660
661
662
663 return cls.getGenericSuperclass();
664 }
665
666
667
668
669
670
671
672
673
674
675
676 public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
677 Objects.requireNonNull(typeVariable, "typeVariable");
678 final Type[] bounds = typeVariable.getBounds();
679
680 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
681 }
682
683
684
685
686
687
688
689
690
691
692
693 public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
694 Objects.requireNonNull(wildcardType, "wildcardType");
695 final Type[] bounds = wildcardType.getLowerBounds();
696
697 return bounds.length == 0 ? new Type[] { null } : bounds;
698 }
699
700
701
702
703
704
705
706
707
708
709
710
711 public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
712 Objects.requireNonNull(wildcardType, "wildcardType");
713 final Type[] bounds = wildcardType.getUpperBounds();
714
715 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
716 }
717
718
719
720
721
722
723
724
725 private static Class<?> getRawType(final ParameterizedType parameterizedType) {
726 final Type rawType = parameterizedType.getRawType();
727
728
729
730
731
732
733 if (!(rawType instanceof Class<?>)) {
734 throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
735 }
736
737 return (Class<?>) rawType;
738 }
739
740
741
742
743
744
745
746
747
748
749
750
751
752 public static Class<?> getRawType(final Type type, final Type assigningType) {
753 if (type instanceof Class<?>) {
754
755 return (Class<?>) type;
756 }
757
758 if (type instanceof ParameterizedType) {
759
760 return getRawType((ParameterizedType) type);
761 }
762
763 if (type instanceof TypeVariable<?>) {
764 if (assigningType == null) {
765 return null;
766 }
767
768
769 final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
770
771
772
773 if (!(genericDeclaration instanceof Class<?>)) {
774 return null;
775 }
776
777
778
779 final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
780 (Class<?>) genericDeclaration);
781
782
783
784 if (typeVarAssigns == null) {
785 return null;
786 }
787
788
789 final Type typeArgument = typeVarAssigns.get(type);
790
791 if (typeArgument == null) {
792 return null;
793 }
794
795
796 return getRawType(typeArgument, assigningType);
797 }
798
799 if (type instanceof GenericArrayType) {
800
801 final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
802 .getGenericComponentType(), assigningType);
803
804
805 return rawComponentType != null ? Array.newInstance(rawComponentType, 0).getClass() : null;
806 }
807
808
809 if (type instanceof WildcardType) {
810 return null;
811 }
812
813 throw new IllegalArgumentException("unknown type: " + type);
814 }
815
816
817
818
819
820
821
822
823
824 private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
825 final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
826
827 if (!isAssignable(cls, toClass)) {
828 return null;
829 }
830
831
832 if (cls.isPrimitive()) {
833
834 if (toClass.isPrimitive()) {
835
836
837 return new HashMap<>();
838 }
839
840
841 cls = ClassUtils.primitiveToWrapper(cls);
842 }
843
844
845 final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
846 : new HashMap<>(subtypeVarAssigns);
847
848
849 if (toClass.equals(cls)) {
850 return typeVarAssigns;
851 }
852
853
854 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
855 }
856
857
858
859
860
861
862
863
864
865
866
867
868
869 public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
870 return getTypeArguments(type, getRawType(type), null);
871 }
872
873
874
875
876
877
878
879
880
881 private static Map<TypeVariable<?>, Type> getTypeArguments(
882 final ParameterizedType parameterizedType, final Class<?> toClass,
883 final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
884 final Class<?> cls = getRawType(parameterizedType);
885
886
887 if (!isAssignable(cls, toClass)) {
888 return null;
889 }
890
891 final Type ownerType = parameterizedType.getOwnerType();
892 final Map<TypeVariable<?>, Type> typeVarAssigns;
893
894 if (ownerType instanceof ParameterizedType) {
895
896 final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
897 typeVarAssigns = getTypeArguments(parameterizedOwnerType,
898 getRawType(parameterizedOwnerType), subtypeVarAssigns);
899 } else {
900
901 typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
902 : new HashMap<>(subtypeVarAssigns);
903 }
904
905
906 final Type[] typeArgs = parameterizedType.getActualTypeArguments();
907
908 final TypeVariable<?>[] typeParams = cls.getTypeParameters();
909
910
911 for (int i = 0; i < typeParams.length; i++) {
912 final Type typeArg = typeArgs[i];
913 typeVarAssigns.put(
914 typeParams[i],
915 typeVarAssigns.getOrDefault(typeArg, typeArg)
916 );
917 }
918
919 if (toClass.equals(cls)) {
920
921 return typeVarAssigns;
922 }
923
924
925 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
926 }
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966 public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
967 return getTypeArguments(type, toClass, null);
968 }
969
970
971
972
973
974
975
976
977
978 private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass,
979 final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
980 if (type instanceof Class<?>) {
981 return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
982 }
983
984 if (type instanceof ParameterizedType) {
985 return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
986 }
987
988 if (type instanceof GenericArrayType) {
989 return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
990 .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
991 }
992
993
994
995 if (type instanceof WildcardType) {
996 for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
997
998 if (isAssignable(bound, toClass)) {
999 return getTypeArguments(bound, toClass, subtypeVarAssigns);
1000 }
1001 }
1002
1003 return null;
1004 }
1005
1006 if (type instanceof TypeVariable<?>) {
1007 for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
1008
1009 if (isAssignable(bound, toClass)) {
1010 return getTypeArguments(bound, toClass, subtypeVarAssigns);
1011 }
1012 }
1013
1014 return null;
1015 }
1016 throw new IllegalStateException("found an unhandled type: " + type);
1017 }
1018
1019
1020
1021
1022
1023
1024
1025 public static boolean isArrayType(final Type type) {
1026 return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
1027 }
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037 private static boolean isAssignable(final Type type, final Class<?> toClass) {
1038 if (type == null) {
1039
1040 return toClass == null || !toClass.isPrimitive();
1041 }
1042
1043
1044
1045 if (toClass == null) {
1046 return false;
1047 }
1048
1049
1050 if (toClass.equals(type)) {
1051 return true;
1052 }
1053
1054 if (type instanceof Class<?>) {
1055
1056 return ClassUtils.isAssignable((Class<?>) type, toClass);
1057 }
1058
1059 if (type instanceof ParameterizedType) {
1060
1061 return isAssignable(getRawType((ParameterizedType) type), toClass);
1062 }
1063
1064
1065 if (type instanceof TypeVariable<?>) {
1066
1067
1068 for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
1069 if (isAssignable(bound, toClass)) {
1070 return true;
1071 }
1072 }
1073
1074 return false;
1075 }
1076
1077
1078
1079 if (type instanceof GenericArrayType) {
1080 return toClass.equals(Object.class)
1081 || toClass.isArray()
1082 && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
1083 .getComponentType());
1084 }
1085
1086
1087
1088 if (type instanceof WildcardType) {
1089 return false;
1090 }
1091
1092 throw new IllegalStateException("found an unhandled type: " + type);
1093 }
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105 private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
1106 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1107 if (type == null) {
1108 return true;
1109 }
1110
1111
1112
1113 if (toGenericArrayType == null) {
1114 return false;
1115 }
1116
1117
1118 if (toGenericArrayType.equals(type)) {
1119 return true;
1120 }
1121
1122 final Type toComponentType = toGenericArrayType.getGenericComponentType();
1123
1124 if (type instanceof Class<?>) {
1125 final Class<?> cls = (Class<?>) type;
1126
1127
1128 return cls.isArray()
1129 && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
1130 }
1131
1132 if (type instanceof GenericArrayType) {
1133
1134 return isAssignable(((GenericArrayType) type).getGenericComponentType(),
1135 toComponentType, typeVarAssigns);
1136 }
1137
1138 if (type instanceof WildcardType) {
1139
1140 for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
1141 if (isAssignable(bound, toGenericArrayType)) {
1142 return true;
1143 }
1144 }
1145
1146 return false;
1147 }
1148
1149 if (type instanceof TypeVariable<?>) {
1150
1151
1152 for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
1153 if (isAssignable(bound, toGenericArrayType)) {
1154 return true;
1155 }
1156 }
1157
1158 return false;
1159 }
1160
1161 if (type instanceof ParameterizedType) {
1162
1163
1164
1165 return false;
1166 }
1167
1168 throw new IllegalStateException("found an unhandled type: " + type);
1169 }
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180 private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
1181 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1182 if (type == null) {
1183 return true;
1184 }
1185
1186
1187
1188 if (toParameterizedType == null) {
1189 return false;
1190 }
1191
1192
1193 if (type instanceof GenericArrayType) {
1194 return false;
1195 }
1196
1197
1198 if (toParameterizedType.equals(type)) {
1199 return true;
1200 }
1201
1202
1203 final Class<?> toClass = getRawType(toParameterizedType);
1204
1205
1206 final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
1207
1208
1209 if (fromTypeVarAssigns == null) {
1210 return false;
1211 }
1212
1213
1214
1215
1216 if (fromTypeVarAssigns.isEmpty()) {
1217 return true;
1218 }
1219
1220
1221 final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
1222 toClass, typeVarAssigns);
1223
1224
1225 for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
1226 final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
1227 final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
1228
1229 if (toTypeArg == null && fromTypeArg instanceof Class) {
1230 continue;
1231 }
1232
1233
1234
1235
1236 if (fromTypeArg != null && toTypeArg != null
1237 && !toTypeArg.equals(fromTypeArg)
1238 && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
1239 typeVarAssigns))) {
1240 return false;
1241 }
1242 }
1243 return true;
1244 }
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256 public static boolean isAssignable(final Type type, final Type toType) {
1257 return isAssignable(type, toType, null);
1258 }
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269 private static boolean isAssignable(final Type type, final Type toType,
1270 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1271 if (toType == null || toType instanceof Class<?>) {
1272 return isAssignable(type, (Class<?>) toType);
1273 }
1274
1275 if (toType instanceof ParameterizedType) {
1276 return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
1277 }
1278
1279 if (toType instanceof GenericArrayType) {
1280 return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
1281 }
1282
1283 if (toType instanceof WildcardType) {
1284 return isAssignable(type, (WildcardType) toType, typeVarAssigns);
1285 }
1286
1287 if (toType instanceof TypeVariable<?>) {
1288 return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
1289 }
1290
1291 throw new IllegalStateException("found an unhandled type: " + toType);
1292 }
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304 private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
1305 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1306 if (type == null) {
1307 return true;
1308 }
1309
1310
1311
1312 if (toTypeVariable == null) {
1313 return false;
1314 }
1315
1316
1317 if (toTypeVariable.equals(type)) {
1318 return true;
1319 }
1320
1321 if (type instanceof TypeVariable<?>) {
1322
1323
1324
1325 final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
1326
1327 for (final Type bound : bounds) {
1328 if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
1329 return true;
1330 }
1331 }
1332 }
1333
1334 if (type instanceof Class<?> || type instanceof ParameterizedType
1335 || type instanceof GenericArrayType || type instanceof WildcardType) {
1336 return false;
1337 }
1338
1339 throw new IllegalStateException("found an unhandled type: " + type);
1340 }
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352 private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
1353 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1354 if (type == null) {
1355 return true;
1356 }
1357
1358
1359
1360 if (toWildcardType == null) {
1361 return false;
1362 }
1363
1364
1365 if (toWildcardType.equals(type)) {
1366 return true;
1367 }
1368
1369 final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
1370 final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
1371
1372 if (type instanceof WildcardType) {
1373 final WildcardType wildcardType = (WildcardType) type;
1374 final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
1375 final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
1376
1377 for (Type toBound : toUpperBounds) {
1378
1379
1380 toBound = substituteTypeVariables(toBound, typeVarAssigns);
1381
1382
1383
1384
1385 for (final Type bound : upperBounds) {
1386 if (!isAssignable(bound, toBound, typeVarAssigns)) {
1387 return false;
1388 }
1389 }
1390 }
1391
1392 for (Type toBound : toLowerBounds) {
1393
1394
1395 toBound = substituteTypeVariables(toBound, typeVarAssigns);
1396
1397
1398
1399
1400 for (final Type bound : lowerBounds) {
1401 if (!isAssignable(toBound, bound, typeVarAssigns)) {
1402 return false;
1403 }
1404 }
1405 }
1406 return true;
1407 }
1408
1409 for (final Type toBound : toUpperBounds) {
1410
1411
1412 if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
1413 typeVarAssigns)) {
1414 return false;
1415 }
1416 }
1417
1418 for (final Type toBound : toLowerBounds) {
1419
1420
1421 if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
1422 typeVarAssigns)) {
1423 return false;
1424 }
1425 }
1426 return true;
1427 }
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437 public static boolean isInstance(final Object value, final Type type) {
1438 if (type == null) {
1439 return false;
1440 }
1441
1442 return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
1443 : isAssignable(value.getClass(), type, null);
1444 }
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454 private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
1455 final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1456
1457 final Type ownerType = parameterizedType.getOwnerType();
1458
1459 if (ownerType instanceof ParameterizedType) {
1460
1461 mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
1462 }
1463
1464
1465
1466
1467
1468 final Type[] typeArgs = parameterizedType.getActualTypeArguments();
1469
1470
1471
1472 final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
1473
1474
1475 final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
1476 .getTypeParameters());
1477
1478 for (int i = 0; i < typeArgs.length; i++) {
1479 final TypeVariable<?> typeVar = typeVars[i];
1480 final Type typeArg = typeArgs[i];
1481
1482
1483 if (typeVarList.contains(typeArg)
1484
1485
1486 && typeVarAssigns.containsKey(typeVar)) {
1487
1488 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
1489 }
1490 }
1491 }
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518 public static Type[] normalizeUpperBounds(final Type[] bounds) {
1519 Objects.requireNonNull(bounds, "bounds");
1520
1521 if (bounds.length < 2) {
1522 return bounds;
1523 }
1524
1525 final Set<Type> types = new HashSet<>(bounds.length);
1526
1527 for (final Type type1 : bounds) {
1528 boolean subtypeFound = false;
1529
1530 for (final Type type2 : bounds) {
1531 if (type1 != type2 && isAssignable(type2, type1, null)) {
1532 subtypeFound = true;
1533 break;
1534 }
1535 }
1536
1537 if (!subtypeFound) {
1538 types.add(type1);
1539 }
1540 }
1541
1542 return types.toArray(ArrayUtils.EMPTY_TYPE_ARRAY);
1543 }
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554 public static final ParameterizedType parameterize(final Class<?> rawClass,
1555 final Map<TypeVariable<?>, Type> typeVariableMap) {
1556 Objects.requireNonNull(rawClass, "rawClass");
1557 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1558 return parameterizeWithOwner(null, rawClass,
1559 extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
1560 }
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571 public static final ParameterizedType parameterize(final Class<?> rawClass, final Type... typeArguments) {
1572 return parameterizeWithOwner(null, rawClass, typeArguments);
1573 }
1574
1575
1576
1577
1578
1579
1580
1581
1582 private static String parameterizedTypeToString(final ParameterizedType parameterizedType) {
1583 final StringBuilder builder = new StringBuilder();
1584
1585 final Type useOwner = parameterizedType.getOwnerType();
1586 final Class<?> raw = (Class<?>) parameterizedType.getRawType();
1587
1588 if (useOwner == null) {
1589 builder.append(raw.getName());
1590 } else {
1591 if (useOwner instanceof Class<?>) {
1592 builder.append(((Class<?>) useOwner).getName());
1593 } else {
1594 builder.append(useOwner.toString());
1595 }
1596 builder.append('.').append(raw.getSimpleName());
1597 }
1598
1599 final int[] recursiveTypeIndexes = findRecursiveTypes(parameterizedType);
1600
1601 if (recursiveTypeIndexes.length > 0) {
1602 appendRecursiveTypes(builder, recursiveTypeIndexes, parameterizedType.getActualTypeArguments());
1603 } else {
1604 appendAllTo(builder.append('<'), ", ", parameterizedType.getActualTypeArguments()).append('>');
1605 }
1606
1607 return builder.toString();
1608 }
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621 public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
1622 final Map<TypeVariable<?>, Type> typeVariableMap) {
1623 Objects.requireNonNull(rawClass, "rawClass");
1624 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1625 return parameterizeWithOwner(owner, rawClass,
1626 extractTypeArgumentsFrom(typeVariableMap, rawClass.getTypeParameters()));
1627 }
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640 public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
1641 final Type... typeArguments) {
1642 Objects.requireNonNull(rawClass, "rawClass");
1643 final Type useOwner;
1644 if (rawClass.getEnclosingClass() == null) {
1645 Validate.isTrue(owner == null, "no owner allowed for top-level %s", rawClass);
1646 useOwner = null;
1647 } else if (owner == null) {
1648 useOwner = rawClass.getEnclosingClass();
1649 } else {
1650 Validate.isTrue(isAssignable(owner, rawClass.getEnclosingClass()),
1651 "%s is invalid owner type for parameterized %s", owner, rawClass);
1652 useOwner = owner;
1653 }
1654 Validate.noNullElements(typeArguments, "null type argument at index %s");
1655 Validate.isTrue(rawClass.getTypeParameters().length == typeArguments.length,
1656 "invalid number of type parameters specified: expected %d, got %d", rawClass.getTypeParameters().length,
1657 typeArguments.length);
1658
1659 return new ParameterizedTypeImpl(rawClass, useOwner, typeArguments);
1660 }
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670 private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1671 if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
1672 final Type replacementType = typeVarAssigns.get(type);
1673
1674 if (replacementType == null) {
1675 throw new IllegalArgumentException("missing assignment type for type variable "
1676 + type);
1677 }
1678 return replacementType;
1679 }
1680 return type;
1681 }
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691 public static String toLongString(final TypeVariable<?> typeVariable) {
1692 Objects.requireNonNull(typeVariable, "typeVariable");
1693 final StringBuilder buf = new StringBuilder();
1694 final GenericDeclaration d = typeVariable.getGenericDeclaration();
1695 if (d instanceof Class<?>) {
1696 Class<?> c = (Class<?>) d;
1697 while (true) {
1698 if (c.getEnclosingClass() == null) {
1699 buf.insert(0, c.getName());
1700 break;
1701 }
1702 buf.insert(0, c.getSimpleName()).insert(0, '.');
1703 c = c.getEnclosingClass();
1704 }
1705 } else if (d instanceof Type) {
1706 buf.append(toString((Type) d));
1707 } else {
1708 buf.append(d);
1709 }
1710 return buf.append(':').append(typeVariableToString(typeVariable)).toString();
1711 }
1712
1713 private static <T> String toString(final T object) {
1714 return object instanceof Type ? toString((Type) object) : object.toString();
1715 }
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725 public static String toString(final Type type) {
1726 Objects.requireNonNull(type, "type");
1727 if (type instanceof Class<?>) {
1728 return classToString((Class<?>) type);
1729 }
1730 if (type instanceof ParameterizedType) {
1731 return parameterizedTypeToString((ParameterizedType) type);
1732 }
1733 if (type instanceof WildcardType) {
1734 return wildcardTypeToString((WildcardType) type);
1735 }
1736 if (type instanceof TypeVariable<?>) {
1737 return typeVariableToString((TypeVariable<?>) type);
1738 }
1739 if (type instanceof GenericArrayType) {
1740 return genericArrayTypeToString((GenericArrayType) type);
1741 }
1742 throw new IllegalArgumentException(ObjectUtils.identityToString(type));
1743 }
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759 public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVariableMap) {
1760 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1761
1762
1763 for (final Map.Entry<TypeVariable<?>, Type> entry : typeVariableMap.entrySet()) {
1764 final TypeVariable<?> typeVar = entry.getKey();
1765 final Type type = entry.getValue();
1766
1767 for (final Type bound : getImplicitBounds(typeVar)) {
1768 if (!isAssignable(type, substituteTypeVariables(bound, typeVariableMap),
1769 typeVariableMap)) {
1770 return false;
1771 }
1772 }
1773 }
1774 return true;
1775 }
1776
1777
1778
1779
1780
1781
1782
1783
1784 private static String typeVariableToString(final TypeVariable<?> typeVariable) {
1785 final StringBuilder buf = new StringBuilder(typeVariable.getName());
1786 final Type[] bounds = typeVariable.getBounds();
1787 if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) {
1788 buf.append(" extends ");
1789 appendAllTo(buf, " & ", typeVariable.getBounds());
1790 }
1791 return buf.toString();
1792 }
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802 private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
1803 Type[] result = bounds;
1804 int i = 0;
1805 for (; i < result.length; i++) {
1806 final Type unrolled = unrollVariables(typeArguments, result[i]);
1807 if (unrolled == null) {
1808 result = ArrayUtils.remove(result, i--);
1809 } else {
1810 result[i] = unrolled;
1811 }
1812 }
1813 return result;
1814 }
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825 private static Type unrollVariableAssignments(TypeVariable<?> typeVariable, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1826 Type result;
1827 do {
1828 result = typeVarAssigns.get(typeVariable);
1829 if (!(result instanceof TypeVariable<?>) || result.equals(typeVariable)) {
1830 break;
1831 }
1832 typeVariable = (TypeVariable<?>) result;
1833 } while (true);
1834 return result;
1835 }
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845 public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
1846 if (typeArguments == null) {
1847 typeArguments = Collections.emptyMap();
1848 }
1849 if (containsTypeVariables(type)) {
1850 if (type instanceof TypeVariable<?>) {
1851 return unrollVariables(typeArguments, typeArguments.get(type));
1852 }
1853 if (type instanceof ParameterizedType) {
1854 final ParameterizedType p = (ParameterizedType) type;
1855 final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
1856 if (p.getOwnerType() == null) {
1857 parameterizedTypeArguments = typeArguments;
1858 } else {
1859 parameterizedTypeArguments = new HashMap<>(typeArguments);
1860 parameterizedTypeArguments.putAll(getTypeArguments(p));
1861 }
1862 final Type[] args = p.getActualTypeArguments();
1863 for (int i = 0; i < args.length; i++) {
1864 final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
1865 if (unrolled != null) {
1866 args[i] = unrolled;
1867 }
1868 }
1869 return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
1870 }
1871 if (type instanceof WildcardType) {
1872 final WildcardType wild = (WildcardType) type;
1873 return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
1874 .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
1875 }
1876 }
1877 return type;
1878 }
1879
1880
1881
1882
1883
1884
1885
1886 public static WildcardTypeBuilder wildcardType() {
1887 return new WildcardTypeBuilder();
1888 }
1889
1890
1891
1892
1893
1894
1895
1896
1897 private static String wildcardTypeToString(final WildcardType wildcardType) {
1898 final StringBuilder buf = new StringBuilder().append('?');
1899 final Type[] lowerBounds = wildcardType.getLowerBounds();
1900 final Type[] upperBounds = wildcardType.getUpperBounds();
1901 if (lowerBounds.length > 1 || lowerBounds.length == 1 && lowerBounds[0] != null) {
1902 appendAllTo(buf.append(" super "), " & ", lowerBounds);
1903 } else if (upperBounds.length > 1 || upperBounds.length == 1 && !Object.class.equals(upperBounds[0])) {
1904 appendAllTo(buf.append(" extends "), " & ", upperBounds);
1905 }
1906 return buf.toString();
1907 }
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917 public static <T> Typed<T> wrap(final Class<T> type) {
1918 return wrap((Type) type);
1919 }
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929 public static <T> Typed<T> wrap(final Type type) {
1930 return () -> type;
1931 }
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942 public TypeUtils() {
1943 }
1944
1945 }