1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.di.impl;
20
21 import java.lang.reflect.*;
22 import java.util.*;
23 import java.util.concurrent.ConcurrentHashMap;
24 import java.util.function.Function;
25
26 import org.apache.maven.api.annotations.Nullable;
27
28 import static java.util.stream.Collectors.joining;
29
30
31
32
33 public class Types {
34 public static final Type[] NO_TYPES = new Type[0];
35 public static final WildcardType WILDCARD_TYPE_ANY = new WildcardTypeImpl(new Type[] {Object.class}, new Type[0]);
36 private static final Map<Type, Map<TypeVariable<?>, Type>> TYPE_BINDINGS_CACHE = new ConcurrentHashMap<>();
37
38
39
40
41
42
43
44 public static Class<?> getRawType(Type type) {
45 if (type instanceof Class) {
46 return (Class<?>) type;
47 } else if (type instanceof ParameterizedType) {
48 return (Class<?>) ((ParameterizedType) type).getRawType();
49 } else if (type instanceof WildcardType) {
50 Type[] upperBounds = ((WildcardType) type).getUpperBounds();
51 return getRawType(getUppermostType(upperBounds));
52 } else if (type instanceof GenericArrayType) {
53 Class<?> rawComponentType = getRawType(((GenericArrayType) type).getGenericComponentType());
54 try {
55 return Class.forName("[L" + rawComponentType.getName() + ";");
56 } catch (ClassNotFoundException e) {
57 throw new RuntimeException(e);
58 }
59 } else if (type instanceof TypeVariable) {
60 return getRawType(getUppermostType(((TypeVariable<?>) type).getBounds()));
61 } else {
62 throw new IllegalArgumentException("Unsupported type: " + type);
63 }
64 }
65
66
67
68
69 public static Type getUppermostType(Type[] types) {
70 Type result = types[0];
71 for (int i = 1; i < types.length; i++) {
72 Type type = types[i];
73 if (isAssignable(type, result)) {
74 result = type;
75 continue;
76 } else if (isAssignable(result, type)) {
77 continue;
78 }
79 throw new IllegalArgumentException("Unrelated types: " + result + " , " + type);
80 }
81 return result;
82 }
83
84
85
86
87
88
89
90 public static Type[] getActualTypeArguments(Type type) {
91 if (type instanceof Class) {
92 return ((Class<?>) type).isArray() ? new Type[] {((Class<?>) type).getComponentType()} : NO_TYPES;
93 } else if (type instanceof ParameterizedType) {
94 return ((ParameterizedType) type).getActualTypeArguments();
95 } else if (type instanceof GenericArrayType) {
96 return new Type[] {((GenericArrayType) type).getGenericComponentType()};
97 }
98 throw new IllegalArgumentException("Unsupported type: " + type);
99 }
100
101
102
103
104 public static Map<TypeVariable<?>, Type> getTypeBindings(Type type) {
105 Type[] typeArguments = getActualTypeArguments(type);
106 if (typeArguments.length == 0) {
107 return Collections.emptyMap();
108 }
109 TypeVariable<?>[] typeVariables = getRawType(type).getTypeParameters();
110 Map<TypeVariable<?>, Type> map = new HashMap<>();
111 for (int i = 0; i < typeVariables.length; i++) {
112 map.put(typeVariables[i], typeArguments[i]);
113 }
114 return map;
115 }
116
117
118
119
120
121 public static Map<TypeVariable<?>, Type> getAllTypeBindings(Type type) {
122 return TYPE_BINDINGS_CACHE.computeIfAbsent(type, t -> {
123 Map<TypeVariable<?>, Type> mapping = new HashMap<>();
124 getAllTypeBindingsImpl(t, mapping);
125 return mapping;
126 });
127 }
128
129 private static void getAllTypeBindingsImpl(Type type, Map<TypeVariable<?>, Type> mapping) {
130 Class<?> cls = getRawType(type);
131
132 if (type instanceof ParameterizedType) {
133 Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
134 if (typeArguments.length != 0) {
135 TypeVariable<? extends Class<?>>[] typeVariables = cls.getTypeParameters();
136 for (int i = 0; i < typeArguments.length; i++) {
137 Type typeArgument = typeArguments[i];
138 mapping.put(
139 typeVariables[i],
140 typeArgument instanceof TypeVariable
141 ? Objects.requireNonNull(mapping.get(typeArgument))
142 : typeArgument);
143 }
144 }
145 }
146
147 Type superclass = cls.getGenericSuperclass();
148 if (superclass != null) {
149 getAllTypeBindingsImpl(superclass, mapping);
150 }
151
152 for (Type anInterface : cls.getGenericInterfaces()) {
153 getAllTypeBindingsImpl(anInterface, mapping);
154 }
155 }
156
157
158
159
160
161
162
163 public static Type bind(Type type, Map<TypeVariable<?>, Type> bindings) {
164 return bind(type, bindings::get);
165 }
166
167
168
169
170
171
172
173 public static Type bind(Type type, Function<TypeVariable<?>, Type> bindings) {
174 if (type instanceof Class) {
175 return type;
176 }
177 if (type instanceof TypeVariable<?>) {
178 TypeVariable<?> typeVariable = (TypeVariable<?>) type;
179 Type actualType = bindings.apply(typeVariable);
180 if (actualType == null) {
181 throw new IllegalArgumentException("Type variable not found: " + typeVariable + " ( "
182 + typeVariable.getGenericDeclaration() + " ) ");
183 }
184 return actualType;
185 }
186 if (type instanceof ParameterizedType) {
187 ParameterizedType parameterizedType = (ParameterizedType) type;
188 Type[] typeArguments = parameterizedType.getActualTypeArguments();
189 Type[] typeArguments2 = new Type[typeArguments.length];
190 for (int i = 0; i < typeArguments.length; i++) {
191 typeArguments2[i] = bind(typeArguments[i], bindings);
192 }
193 return new ParameterizedTypeImpl(
194 parameterizedType.getOwnerType(), parameterizedType.getRawType(), typeArguments2);
195 }
196 if (type instanceof GenericArrayType) {
197 Type componentType = ((GenericArrayType) type).getGenericComponentType();
198 return new GenericArrayTypeImpl(bind(componentType, bindings));
199 }
200 if (type instanceof WildcardType) {
201 WildcardType wildcardType = (WildcardType) type;
202 Type[] upperBounds = wildcardType.getUpperBounds();
203 Type[] upperBounds2 = new Type[upperBounds.length];
204 for (int i = 0; i < upperBounds.length; i++) {
205 upperBounds2[i] = bind(upperBounds[i], bindings);
206 }
207 Type[] lowerBounds = wildcardType.getLowerBounds();
208 Type[] lowerBounds2 = new Type[lowerBounds.length];
209 for (int i = 0; i < lowerBounds.length; i++) {
210 lowerBounds2[i] = bind(lowerBounds[i], bindings);
211 }
212 return new WildcardTypeImpl(upperBounds2, lowerBounds2);
213 }
214 throw new IllegalArgumentException("Unsupported type: " + type);
215 }
216
217
218
219
220
221
222
223
224
225 public static ParameterizedType parameterizedType(@Nullable Type ownerType, Type rawType, Type[] parameters) {
226 return new ParameterizedTypeImpl(ownerType, rawType, parameters);
227 }
228
229
230
231
232
233
234 public static ParameterizedType parameterizedType(Class<?> rawType, Type... parameters) {
235 return new ParameterizedTypeImpl(null, rawType, parameters);
236 }
237
238
239
240
241 public static Set<Type> getAllSuperTypes(Type original) {
242 Deque<Type> todo = new ArrayDeque<>();
243 todo.add(original);
244 Set<Type> done = new HashSet<>();
245 while (!todo.isEmpty()) {
246 Type type = todo.remove();
247 if (done.add(type)) {
248 Class<?> cls = getRawType(type);
249 Function<TypeVariable<?>, Type> bindings;
250 if (type instanceof ParameterizedType) {
251 Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
252 TypeVariable<? extends Class<?>>[] typeVariables = cls.getTypeParameters();
253 bindings = v -> {
254 for (int i = 0; i < typeArguments.length; i++) {
255 Type typeArgument = typeArguments[i];
256 if (v.equals(typeVariables[i])) {
257 return typeArgument;
258 }
259 }
260 return null;
261 };
262 } else {
263 bindings = v -> null;
264 }
265 Type[] interfaces = cls.getGenericInterfaces();
266 for (Type itf : interfaces) {
267 todo.add(bind(itf, bindings));
268 }
269 Type supercls = cls.getGenericSuperclass();
270 if (supercls != null) {
271 todo.add(bind(supercls, bindings));
272 }
273 }
274 }
275 return done;
276 }
277
278 public static Type simplifyType(Type original) {
279 if (original instanceof Class) {
280 return original;
281 }
282
283 if (original instanceof GenericArrayType) {
284 Type componentType = ((GenericArrayType) original).getGenericComponentType();
285 Type repackedComponentType = simplifyType(componentType);
286 if (componentType != repackedComponentType) {
287 return genericArrayType(repackedComponentType);
288 }
289 return original;
290 }
291
292 if (original instanceof ParameterizedType) {
293 ParameterizedType parameterizedType = (ParameterizedType) original;
294 Type[] typeArguments = parameterizedType.getActualTypeArguments();
295 Type[] repackedTypeArguments = simplifyTypes(typeArguments);
296
297 if (isAllObjects(repackedTypeArguments)) {
298 return parameterizedType.getRawType();
299 }
300
301 if (typeArguments != repackedTypeArguments) {
302 return parameterizedType(
303 parameterizedType.getOwnerType(), parameterizedType.getRawType(), repackedTypeArguments);
304 }
305 return original;
306 }
307
308 if (original instanceof TypeVariable) {
309 throw new IllegalArgumentException("Key should not contain a type variable: " + original);
310 }
311
312 if (original instanceof WildcardType) {
313 WildcardType wildcardType = (WildcardType) original;
314 Type[] upperBounds = wildcardType.getUpperBounds();
315 if (upperBounds.length == 1) {
316 Type upperBound = upperBounds[0];
317 if (upperBound != Object.class) {
318 return simplifyType(upperBound);
319 }
320 } else if (upperBounds.length > 1) {
321 throw new IllegalArgumentException("Multiple upper bounds not supported: " + original);
322 }
323
324 Type[] lowerBounds = wildcardType.getLowerBounds();
325 if (lowerBounds.length == 1) {
326 return simplifyType(lowerBounds[0]);
327 } else if (lowerBounds.length > 1) {
328 throw new IllegalArgumentException("Multiple lower bounds not supported: " + original);
329 }
330 return Object.class;
331 }
332
333 return original;
334 }
335
336 private static Type[] simplifyTypes(Type[] original) {
337 int length = original.length;
338 for (int i = 0; i < length; i++) {
339 Type typeArgument = original[i];
340 Type repackTypeArgument = simplifyType(typeArgument);
341 if (repackTypeArgument != typeArgument) {
342 Type[] repackedTypeArguments = new Type[length];
343 System.arraycopy(original, 0, repackedTypeArguments, 0, i);
344 repackedTypeArguments[i++] = repackTypeArgument;
345 for (; i < length; i++) {
346 repackedTypeArguments[i] = simplifyType(original[i]);
347 }
348 return repackedTypeArguments;
349 }
350 }
351 return original;
352 }
353
354 private static boolean isAllObjects(Type[] types) {
355 for (Type type : types) {
356 if (type != Object.class) {
357 return false;
358 }
359 }
360 return true;
361 }
362
363
364
365
366
367
368
369
370 public static boolean isAssignable(Type to, Type from) {
371
372 if (to instanceof Class && from instanceof Class) {
373 return ((Class<?>) to).isAssignableFrom((Class<?>) from);
374 }
375 return isAssignable(to, from, false);
376 }
377
378 private static boolean isAssignable(Type to, Type from, boolean strict) {
379 if (to instanceof WildcardType || from instanceof WildcardType) {
380 Type[] toUppers, toLowers;
381 if (to instanceof WildcardType) {
382 WildcardType wildcardTo = (WildcardType) to;
383 toUppers = wildcardTo.getUpperBounds();
384 toLowers = wildcardTo.getLowerBounds();
385 } else {
386 toUppers = new Type[] {to};
387 toLowers = strict ? toUppers : NO_TYPES;
388 }
389
390 Type[] fromUppers, fromLowers;
391 if (from instanceof WildcardType) {
392 WildcardType wildcardTo = (WildcardType) to;
393 fromUppers = wildcardTo.getUpperBounds();
394 fromLowers = wildcardTo.getLowerBounds();
395 } else {
396 fromUppers = new Type[] {from};
397 fromLowers = strict ? fromUppers : NO_TYPES;
398 }
399
400 for (Type toUpper : toUppers) {
401 for (Type fromUpper : fromUppers) {
402 if (!isAssignable(toUpper, fromUpper, false)) {
403 return false;
404 }
405 }
406 }
407 if (toLowers.length == 0) {
408 return true;
409 }
410 if (fromLowers.length == 0) {
411 return false;
412 }
413 for (Type toLower : toLowers) {
414 for (Type fromLower : fromLowers) {
415 if (!isAssignable(fromLower, toLower, false)) {
416 return false;
417 }
418 }
419 }
420 return true;
421 }
422 if (to instanceof GenericArrayType) {
423 to = getRawType(to);
424 }
425 if (from instanceof GenericArrayType) {
426 from = getRawType(from);
427 }
428 if (!strict && to instanceof Class) {
429 return ((Class<?>) to).isAssignableFrom(getRawType(from));
430 }
431 Class<?> toRawClazz = getRawType(to);
432 Type[] toTypeArguments = getActualTypeArguments(to);
433 return isAssignable(toRawClazz, toTypeArguments, from, strict);
434 }
435
436 private static boolean isAssignable(Class<?> toRawClazz, Type[] toTypeArguments, Type from, boolean strict) {
437 Class<?> fromRawClazz = getRawType(from);
438 if (strict && !toRawClazz.equals(fromRawClazz)) {
439 return false;
440 }
441 if (!strict && !toRawClazz.isAssignableFrom(fromRawClazz)) {
442 return false;
443 }
444 if (toRawClazz.isArray()) {
445 return true;
446 }
447 Type[] fromTypeArguments = getActualTypeArguments(from);
448 if (toRawClazz == fromRawClazz) {
449 if (toTypeArguments.length > fromTypeArguments.length) {
450 return false;
451 }
452 for (int i = 0; i < toTypeArguments.length; i++) {
453 if (!isAssignable(toTypeArguments[i], fromTypeArguments[i], true)) {
454 return false;
455 }
456 }
457 return true;
458 }
459 Map<TypeVariable<?>, Type> typeBindings = getTypeBindings(from);
460 for (Type anInterface : fromRawClazz.getGenericInterfaces()) {
461 if (isAssignable(
462 toRawClazz,
463 toTypeArguments,
464 bind(anInterface, key -> typeBindings.getOrDefault(key, wildcardTypeAny())),
465 false)) {
466 return true;
467 }
468 }
469 Type superclass = fromRawClazz.getGenericSuperclass();
470 return superclass != null && isAssignable(toRawClazz, toTypeArguments, bind(superclass, typeBindings), false);
471 }
472
473 public static final class ParameterizedTypeImpl implements ParameterizedType {
474 private final @Nullable Type ownerType;
475 private final Type rawType;
476 private final Type[] actualTypeArguments;
477
478 ParameterizedTypeImpl(@Nullable Type ownerType, Type rawType, Type[] actualTypeArguments) {
479 this.ownerType = ownerType;
480 this.rawType = rawType;
481 this.actualTypeArguments = actualTypeArguments;
482 }
483
484 @Override
485 public Type getRawType() {
486 return rawType;
487 }
488
489 @Override
490 public Type[] getActualTypeArguments() {
491 return actualTypeArguments;
492 }
493
494 @Override
495 public @Nullable Type getOwnerType() {
496 return ownerType;
497 }
498
499 @Override
500 public int hashCode() {
501 return Objects.hashCode(ownerType) ^ Arrays.hashCode(actualTypeArguments) ^ rawType.hashCode();
502 }
503
504 @Override
505 public boolean equals(Object other) {
506 if (!(other instanceof ParameterizedType)) {
507 return false;
508 }
509 ParameterizedType that = (ParameterizedType) other;
510 return this.getRawType().equals(that.getRawType())
511 && Objects.equals(this.getOwnerType(), that.getOwnerType())
512 && Arrays.equals(this.getActualTypeArguments(), that.getActualTypeArguments());
513 }
514
515 @Override
516 public String toString() {
517 return rawType.getTypeName()
518 + Arrays.stream(actualTypeArguments).map(Types::toString).collect(joining(", ", "<", ">"));
519 }
520 }
521
522
523
524
525
526
527
528
529 public static WildcardType wildcardType(Type[] upperBounds, Type[] lowerBounds) {
530 return new WildcardTypeImpl(upperBounds, lowerBounds);
531 }
532
533
534
535
536
537
538
539
540 public static WildcardType wildcardTypeAny() {
541 return WILDCARD_TYPE_ANY;
542 }
543
544
545
546
547
548
549
550
551
552
553 public static WildcardType wildcardTypeExtends(Type upperBound) {
554 return new WildcardTypeImpl(new Type[] {upperBound}, NO_TYPES);
555 }
556
557
558
559
560
561
562
563
564
565
566 public static WildcardType wildcardTypeSuper(Type lowerBound) {
567 return new WildcardTypeImpl(NO_TYPES, new Type[] {lowerBound});
568 }
569
570 public static class WildcardTypeImpl implements WildcardType {
571 private final Type[] upperBounds;
572 private final Type[] lowerBounds;
573
574 WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
575 this.upperBounds = upperBounds;
576 this.lowerBounds = lowerBounds;
577 }
578
579 @Override
580 public Type[] getUpperBounds() {
581 return upperBounds;
582 }
583
584 @Override
585 public Type[] getLowerBounds() {
586 return lowerBounds;
587 }
588
589 @Override
590 public int hashCode() {
591 return Arrays.hashCode(upperBounds) ^ Arrays.hashCode(lowerBounds);
592 }
593
594 @Override
595 public boolean equals(Object other) {
596 if (!(other instanceof WildcardType)) {
597 return false;
598 }
599 WildcardType that = (WildcardType) other;
600 return Arrays.equals(this.getUpperBounds(), that.getUpperBounds())
601 && Arrays.equals(this.getLowerBounds(), that.getLowerBounds());
602 }
603
604 @Override
605 public String toString() {
606 return "?"
607 + (upperBounds.length == 0
608 ? ""
609 : " extends "
610 + Arrays.stream(upperBounds)
611 .map(Types::toString)
612 .collect(joining(" & ")))
613 + (lowerBounds.length == 0
614 ? ""
615 : " super "
616 + Arrays.stream(lowerBounds)
617 .map(Types::toString)
618 .collect(joining(" & ")));
619 }
620 }
621
622
623
624
625
626
627
628
629
630
631 public static GenericArrayType genericArrayType(Type componentType) {
632 return new GenericArrayTypeImpl(componentType);
633 }
634
635 public static final class GenericArrayTypeImpl implements GenericArrayType {
636 private final Type componentType;
637
638 GenericArrayTypeImpl(Type componentType) {
639 this.componentType = componentType;
640 }
641
642 @Override
643 public Type getGenericComponentType() {
644 return componentType;
645 }
646
647 @Override
648 public int hashCode() {
649 return componentType.hashCode();
650 }
651
652 @Override
653 public boolean equals(Object other) {
654 if (!(other instanceof GenericArrayType)) {
655 return false;
656 }
657 GenericArrayType that = (GenericArrayType) other;
658 return this.getGenericComponentType().equals(that.getGenericComponentType());
659 }
660
661 @Override
662 public String toString() {
663 return Types.toString(componentType) + "[]";
664 }
665 }
666
667 private static String toString(Type type) {
668 return type instanceof Class ? ((Class<?>) type).getName() : type.toString();
669 }
670
671
672
673
674
675
676 public static String getSimpleName(Type type) {
677 if (type instanceof Class) {
678 return ((Class<?>) type).getSimpleName();
679 } else if (type instanceof ParameterizedType) {
680 return Arrays.stream(((ParameterizedType) type).getActualTypeArguments())
681 .map(Types::getSimpleName)
682 .collect(joining(",", "<", ">"));
683 } else if (type instanceof WildcardType) {
684 WildcardType wildcardType = (WildcardType) type;
685 Type[] upperBounds = wildcardType.getUpperBounds();
686 Type[] lowerBounds = wildcardType.getLowerBounds();
687 return "?"
688 + (upperBounds.length == 0
689 ? ""
690 : " extends "
691 + Arrays.stream(upperBounds)
692 .map(Types::getSimpleName)
693 .collect(joining(" & ")))
694 + (lowerBounds.length == 0
695 ? ""
696 : " super "
697 + Arrays.stream(lowerBounds)
698 .map(Types::getSimpleName)
699 .collect(joining(" & ")));
700 } else if (type instanceof GenericArrayType) {
701 return Types.getSimpleName(((GenericArrayType) type).getGenericComponentType()) + "[]";
702 }
703
704 return type.getTypeName();
705 }
706 }