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 (int i = 0; i < recursiveTypeIndexes.length; i++) {
332
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
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 CTJ_JOINER.join(buf, (TypeVariable[]) 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 return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
845 }
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872 public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
873 return getTypeArguments(type, toClass, null);
874 }
875
876
877
878
879
880
881
882
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
896
897 if (type instanceof WildcardType) {
898 for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
899
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
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
920
921
922
923
924 public static boolean isArrayType(final Type type) {
925 return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
926 }
927
928
929
930
931
932
933
934
935 private static boolean isAssignable(final Type type, final Class<?> toClass) {
936 if (type == null) {
937
938 return toClass == null || !toClass.isPrimitive();
939 }
940
941
942 if (toClass == null) {
943 return false;
944 }
945
946 if (toClass.equals(type)) {
947 return true;
948 }
949 if (type instanceof Class<?>) {
950
951 return ClassUtils.isAssignable((Class<?>) type, toClass);
952 }
953 if (type instanceof ParameterizedType) {
954
955 return isAssignable(getRawType((ParameterizedType) type), toClass);
956 }
957
958 if (type instanceof TypeVariable<?>) {
959
960
961 for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
962 if (isAssignable(bound, toClass)) {
963 return true;
964 }
965 }
966 return false;
967 }
968
969
970 if (type instanceof GenericArrayType) {
971 return toClass.equals(Object.class)
972 || toClass.isArray() && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass.getComponentType());
973 }
974
975
976 if (type instanceof WildcardType) {
977 return false;
978 }
979 throw new IllegalStateException("found an unhandled type: " + type);
980 }
981
982
983
984
985
986
987
988
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
995
996 if (toGenericArrayType == null) {
997 return false;
998 }
999
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
1007 return cls.isArray() && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
1008 }
1009 if (type instanceof GenericArrayType) {
1010
1011 return isAssignable(((GenericArrayType) type).getGenericComponentType(), toComponentType, typeVarAssigns);
1012 }
1013 if (type instanceof WildcardType) {
1014
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
1024
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
1034
1035
1036 return false;
1037 }
1038 throw new IllegalStateException("found an unhandled type: " + type);
1039 }
1040
1041
1042
1043
1044
1045
1046
1047
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
1054
1055 if (toParameterizedType == null) {
1056 return false;
1057 }
1058
1059 if (type instanceof GenericArrayType) {
1060 return false;
1061 }
1062
1063 if (toParameterizedType.equals(type)) {
1064 return true;
1065 }
1066
1067 final Class<?> toClass = getRawType(toParameterizedType);
1068
1069
1070 final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
1071
1072 if (fromTypeVarAssigns == null) {
1073 return false;
1074 }
1075
1076
1077
1078 if (fromTypeVarAssigns.isEmpty()) {
1079 return true;
1080 }
1081
1082 final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType, toClass, typeVarAssigns);
1083
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
1091
1092
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
1103
1104
1105
1106
1107
1108
1109 public static boolean isAssignable(final Type type, final Type toType) {
1110 return isAssignable(type, toType, null);
1111 }
1112
1113
1114
1115
1116
1117
1118
1119
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
1142
1143
1144
1145
1146
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
1153
1154 if (toTypeVariable == null) {
1155 return false;
1156 }
1157
1158 if (toTypeVariable.equals(type)) {
1159 return true;
1160 }
1161 if (type instanceof TypeVariable<?>) {
1162
1163
1164
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
1180
1181
1182
1183
1184
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
1191
1192 if (toWildcardType == null) {
1193 return false;
1194 }
1195
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
1207
1208 toBound = substituteTypeVariables(toBound, typeVarAssigns);
1209
1210
1211
1212 for (final Type bound : upperBounds) {
1213 if (!isAssignable(bound, toBound, typeVarAssigns)) {
1214 return false;
1215 }
1216 }
1217 }
1218 for (Type toBound : toLowerBounds) {
1219
1220
1221 toBound = substituteTypeVariables(toBound, typeVarAssigns);
1222
1223
1224
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
1235
1236 if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns), typeVarAssigns)) {
1237 return false;
1238 }
1239 }
1240 for (final Type toBound : toLowerBounds) {
1241
1242
1243 if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type, typeVarAssigns)) {
1244 return false;
1245 }
1246 }
1247 return true;
1248 }
1249
1250
1251
1252
1253
1254
1255
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
1270
1271
1272
1273
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
1284
1285
1286
1287
1288
1289
1290 private static <T> void mapTypeVariablesToArguments(final Class<T> cls, final ParameterizedType parameterizedType,
1291 final Map<TypeVariable<?>, Type> typeVarAssigns) {
1292
1293 final Type ownerType = parameterizedType.getOwnerType();
1294 if (ownerType instanceof ParameterizedType) {
1295
1296 mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
1297 }
1298
1299
1300
1301
1302 final Type[] typeArgs = parameterizedType.getActualTypeArguments();
1303
1304
1305 final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
1306
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
1312 if (typeVarList.contains(typeArg)
1313
1314
1315 && typeVarAssigns.containsKey(typeVar)) {
1316
1317 typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
1318 }
1319 }
1320 }
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346 public static Type[] normalizeUpperBounds(final Type[] bounds) {
1347 Objects.requireNonNull(bounds, "bounds");
1348
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
1370
1371
1372
1373
1374
1375 private static Type[] normalizeUpperToObject(final Type[] bounds) {
1376 return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
1377 }
1378
1379
1380
1381
1382
1383
1384
1385
1386
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
1396
1397
1398
1399
1400
1401
1402
1403 public static final ParameterizedType parameterize(final Class<?> rawClass, final Type... typeArguments) {
1404 return parameterizeWithOwner(null, rawClass, typeArguments);
1405 }
1406
1407
1408
1409
1410
1411
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
1438
1439
1440
1441
1442
1443
1444
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
1454
1455
1456
1457
1458
1459
1460
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
1482
1483
1484
1485
1486
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
1501
1502
1503
1504
1505
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) {
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
1531
1532
1533
1534
1535
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
1559
1560
1561
1562
1563
1564
1565
1566 public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVariableMap) {
1567 Objects.requireNonNull(typeVariableMap, "typeVariableMap");
1568
1569
1570 for (final Map.Entry<TypeVariable<?>, Type> entry : typeVariableMap.entrySet()) {
1571 final TypeVariable<?> typeVar = entry.getKey();
1572 final Type type = entry.getValue();
1573
1574 for (final Type bound : getImplicitBounds(typeVar)) {
1575 if (!isAssignable(type, substituteTypeVariables(bound, typeVariableMap), typeVariableMap)) {
1576 return false;
1577 }
1578 }
1579 }
1580 return true;
1581 }
1582
1583
1584
1585
1586
1587
1588
1589 private static String typeVariableToString(final TypeVariable<?> typeVariable) {
1590 final StringBuilder builder = new StringBuilder(typeVariable.getName());
1591 final Type[] bounds = typeVariable.getBounds();
1592 if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) {
1593
1594
1595
1596 final Type bound = bounds[0];
1597 boolean append = true;
1598 if (bound instanceof ParameterizedType) {
1599 final Type rawType = ((ParameterizedType) bound).getRawType();
1600 if (rawType instanceof Class && ((Class<?>) rawType).isInterface()) {
1601
1602 append = false;
1603 }
1604 }
1605 if (append) {
1606 builder.append(" extends ");
1607 AMP_JOINER.join(builder, bounds);
1608 }
1609 }
1610 return builder.toString();
1611 }
1612
1613
1614
1615
1616
1617
1618
1619
1620 private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
1621 Type[] result = bounds;
1622 int i = 0;
1623 for (; i < result.length; i++) {
1624 final Type unrolled = unrollVariables(typeArguments, result[i]);
1625 if (unrolled == null) {
1626 result = ArrayUtils.remove(result, i--);
1627 } else {
1628 result[i] = unrolled;
1629 }
1630 }
1631 return result;
1632 }
1633
1634
1635
1636
1637
1638
1639
1640
1641 private static Type unrollVariableAssignments(TypeVariable<?> typeVariable, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1642 Type result;
1643 do {
1644 result = typeVarAssigns.get(typeVariable);
1645 if (!(result instanceof TypeVariable<?>) || result.equals(typeVariable)) {
1646 break;
1647 }
1648 typeVariable = (TypeVariable<?>) result;
1649 } while (true);
1650 return result;
1651 }
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661 public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
1662 if (typeArguments == null) {
1663 typeArguments = Collections.emptyMap();
1664 }
1665 if (containsTypeVariables(type)) {
1666 if (type instanceof TypeVariable<?>) {
1667 return unrollVariables(typeArguments, typeArguments.get(type));
1668 }
1669 if (type instanceof ParameterizedType) {
1670 final ParameterizedType p = (ParameterizedType) type;
1671 final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
1672 if (p.getOwnerType() == null) {
1673 parameterizedTypeArguments = typeArguments;
1674 } else {
1675 parameterizedTypeArguments = new HashMap<>(typeArguments);
1676 parameterizedTypeArguments.putAll(getTypeArguments(p));
1677 }
1678 final Type[] args = p.getActualTypeArguments();
1679 for (int i = 0; i < args.length; i++) {
1680 final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
1681 if (unrolled != null) {
1682 args[i] = unrolled;
1683 }
1684 }
1685 return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
1686 }
1687 if (type instanceof WildcardType) {
1688 final WildcardType wild = (WildcardType) type;
1689 return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
1690 .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
1691 }
1692 }
1693 return type;
1694 }
1695
1696
1697
1698
1699
1700
1701
1702 public static WildcardTypeBuilder wildcardType() {
1703 return new WildcardTypeBuilder();
1704 }
1705
1706
1707
1708
1709
1710
1711
1712 private static String wildcardTypeToString(final WildcardType wildcardType) {
1713 final StringBuilder builder = new StringBuilder().append('?');
1714 final Type[] lowerBounds = wildcardType.getLowerBounds();
1715 final Type[] upperBounds = wildcardType.getUpperBounds();
1716 if (lowerBounds.length > 1 || lowerBounds.length == 1 && lowerBounds[0] != null) {
1717 AMP_JOINER.join(builder.append(" super "), lowerBounds);
1718 } else if (upperBounds.length > 1 || upperBounds.length == 1 && !Object.class.equals(upperBounds[0])) {
1719 AMP_JOINER.join(builder.append(" extends "), upperBounds);
1720 }
1721 return builder.toString();
1722 }
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732 public static <T> Typed<T> wrap(final Class<T> type) {
1733 return wrap((Type) type);
1734 }
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744 public static <T> Typed<T> wrap(final Type type) {
1745 return () -> type;
1746 }
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757 @Deprecated
1758 public TypeUtils() {
1759
1760 }
1761
1762 }