1
16 package net.bytebuddy.implementation.bytecode.assign.reference;
17
18 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.type.TypeDescription;
20 import net.bytebuddy.description.type.TypeList;
21 import net.bytebuddy.implementation.bytecode.StackManipulation;
22 import net.bytebuddy.implementation.bytecode.assign.Assigner;
23 import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
24
25 import java.util.*;
26
27
35 public enum GenericTypeAwareAssigner implements Assigner {
36
37
40 INSTANCE;
41
42 @Override
43 public StackManipulation assign(TypeDescription.Generic source, TypeDescription.Generic target, Typing typing) {
44 if (source.isPrimitive() || target.isPrimitive()) {
45 return source.equals(target)
46 ? StackManipulation.Trivial.INSTANCE
47 : StackManipulation.Illegal.INSTANCE;
48 } else if (source.accept(new IsAssignableToVisitor(target))) {
49 return StackManipulation.Trivial.INSTANCE;
50 } else if (typing.isDynamic()) {
51 return source.asErasure().isAssignableTo(target.asErasure())
52 ? StackManipulation.Trivial.INSTANCE
53 : TypeCasting.to(target);
54 } else {
55 return StackManipulation.Illegal.INSTANCE;
56 }
57 }
58
59
62 @HashCodeAndEqualsPlugin.Enhance
63 protected static class IsAssignableToVisitor implements TypeDescription.Generic.Visitor<Boolean> {
64
65
68 private final TypeDescription.Generic typeDescription;
69
70
73 private final boolean polymorphic;
74
75
80 public IsAssignableToVisitor(TypeDescription.Generic typeDescription) {
81 this(typeDescription, true);
82 }
83
84
90 protected IsAssignableToVisitor(TypeDescription.Generic typeDescription, boolean polymorphic) {
91 this.typeDescription = typeDescription;
92 this.polymorphic = polymorphic;
93 }
94
95
98 public Boolean onGenericArray(TypeDescription.Generic genericArray) {
99 return typeDescription.accept(new OfGenericArray(genericArray, polymorphic));
100 }
101
102
105 public Boolean onWildcard(TypeDescription.Generic wildcard) {
106 return typeDescription.accept(new OfWildcard(wildcard));
107 }
108
109
112 public Boolean onParameterizedType(TypeDescription.Generic parameterizedType) {
113 return typeDescription.accept(new OfParameterizedType(parameterizedType, polymorphic));
114 }
115
116
119 public Boolean onTypeVariable(TypeDescription.Generic typeVariable) {
120 if (typeVariable.getTypeVariableSource().isInferrable()) {
121 throw new UnsupportedOperationException("Assignability checks for type variables declared by methods are not currently supported");
122 } else if (typeVariable.equals(typeDescription)) {
123 return true;
124 } else if (polymorphic) {
125 Queue<TypeDescription.Generic> candidates = new LinkedList<TypeDescription.Generic>(typeVariable.getUpperBounds());
126 while (!candidates.isEmpty()) {
127 TypeDescription.Generic candidate = candidates.remove();
128 if (candidate.accept(new IsAssignableToVisitor(typeDescription))) {
129 return true;
130 } else if (candidate.getSort().isTypeVariable()) {
131 candidates.addAll(candidate.getUpperBounds());
132 }
133 }
134 return false;
135 } else {
136 return false;
137 }
138 }
139
140
143 public Boolean onNonGenericType(TypeDescription.Generic typeDescription) {
144 return this.typeDescription.accept(new OfNonGenericType(typeDescription, polymorphic));
145 }
146
147
150 @HashCodeAndEqualsPlugin.Enhance
151 protected abstract static class OfManifestType implements TypeDescription.Generic.Visitor<Boolean> {
152
153
156 protected final TypeDescription.Generic typeDescription;
157
158
161 protected final boolean polymorphic;
162
163
169 protected OfManifestType(TypeDescription.Generic typeDescription, boolean polymorphic) {
170 this.typeDescription = typeDescription;
171 this.polymorphic = polymorphic;
172 }
173
174
177 public Boolean onWildcard(TypeDescription.Generic wildcard) {
178 for (TypeDescription.Generic upperBound : wildcard.getUpperBounds()) {
179 if (!typeDescription.accept(new IsAssignableToVisitor(upperBound))) {
180 return false;
181 }
182 }
183 for (TypeDescription.Generic lowerBound : wildcard.getLowerBounds()) {
184 if (!lowerBound.accept(new IsAssignableToVisitor(typeDescription))) {
185 return false;
186 }
187 }
188 return true;
189 }
190
191
194 public Boolean onTypeVariable(TypeDescription.Generic typeVariable) {
195 if (typeVariable.getTypeVariableSource().isInferrable()) {
196 throw new UnsupportedOperationException("Assignability checks for type variables declared by methods arel not currently supported");
197 } else {
198 return false;
199 }
200 }
201 }
202
203
206 protected abstract static class OfSimpleType extends OfManifestType {
207
208
214 protected OfSimpleType(TypeDescription.Generic typeDescription, boolean polymorphic) {
215 super(typeDescription, polymorphic);
216 }
217
218
221 public Boolean onParameterizedType(TypeDescription.Generic parameterizedType) {
222 Queue<TypeDescription.Generic> candidates = new LinkedList<TypeDescription.Generic>(Collections.singleton(typeDescription));
223 Set<TypeDescription> previous = new HashSet<TypeDescription>(Collections.singleton(typeDescription.asErasure()));
224 do {
225 TypeDescription.Generic candidate = candidates.remove();
226 if (candidate.asErasure().equals(parameterizedType.asErasure())) {
227 if (candidate.getSort().isNonGeneric()) {
228 return true;
229 } else {
230 TypeList.Generic source = candidate.getTypeArguments(), target = parameterizedType.getTypeArguments();
231 int size = target.size();
232 if (source.size() != size) {
233 return false;
234 }
235 for (int index = 0; index < size; index++) {
236 if (!source.get(index).accept(new IsAssignableToVisitor(target.get(index), false))) {
237 return false;
238 }
239 }
240 TypeDescription.Generic ownerType = parameterizedType.getOwnerType();
241 return ownerType == null || ownerType.accept(new IsAssignableToVisitor(parameterizedType.getOwnerType()));
242 }
243 } else if (polymorphic) {
244 TypeDescription.Generic superClass = candidate.getSuperClass();
245 if (superClass != null && previous.add(superClass.asErasure())) {
246 candidates.add(superClass);
247 }
248 for (TypeDescription.Generic anInterface : candidate.getInterfaces()) {
249 if (previous.add(anInterface.asErasure())) {
250 candidates.add(anInterface);
251 }
252 }
253 }
254 } while (!candidates.isEmpty());
255 return false;
256 }
257
258
261 public Boolean onNonGenericType(TypeDescription.Generic typeDescription) {
262 return polymorphic
263 ? this.typeDescription.asErasure().isAssignableTo(typeDescription.asErasure())
264 : this.typeDescription.asErasure().equals(typeDescription.asErasure());
265 }
266 }
267
268
271 protected static class OfGenericArray extends OfManifestType {
272
273
279 protected OfGenericArray(TypeDescription.Generic typeDescription, boolean polymorphic) {
280 super(typeDescription, polymorphic);
281 }
282
283
286 public Boolean onGenericArray(TypeDescription.Generic genericArray) {
287 TypeDescription.Generic source = typeDescription.getComponentType(), target = genericArray.getComponentType();
288 while (source.getSort().isGenericArray() && target.getSort().isGenericArray()) {
289 source = source.getComponentType();
290 target = target.getComponentType();
291 }
292 return !source.getSort().isGenericArray() && !target.getSort().isGenericArray() && source.accept(new IsAssignableToVisitor(target));
293 }
294
295
298 public Boolean onParameterizedType(TypeDescription.Generic parameterizedType) {
299 return false;
300 }
301
302
305 public Boolean onNonGenericType(TypeDescription.Generic typeDescription) {
306 return polymorphic
307 ? this.typeDescription.asErasure().isAssignableTo(typeDescription.asErasure())
308 : this.typeDescription.asErasure().equals(typeDescription.asErasure());
309 }
310 }
311
312
315 @HashCodeAndEqualsPlugin.Enhance
316 protected static class OfWildcard implements TypeDescription.Generic.Visitor<Boolean> {
317
318
321 private final TypeDescription.Generic wildcard;
322
323
328 protected OfWildcard(TypeDescription.Generic wildcard) {
329 this.wildcard = wildcard;
330 }
331
332
335 public Boolean onGenericArray(TypeDescription.Generic genericArray) {
336 return false;
337 }
338
339
342 public Boolean onWildcard(TypeDescription.Generic wildcard) {
343 boolean hasUpperBounds = false, hasLowerBounds = false;
344 for (TypeDescription.Generic target : wildcard.getUpperBounds()) {
345 for (TypeDescription.Generic source : this.wildcard.getUpperBounds()) {
346 if (!source.accept(new IsAssignableToVisitor(target))) {
347 return false;
348 }
349 }
350 hasUpperBounds = hasUpperBounds || !target.represents(Object.class);
351 }
352 for (TypeDescription.Generic target : wildcard.getLowerBounds()) {
353 for (TypeDescription.Generic source : this.wildcard.getLowerBounds()) {
354 if (!target.accept(new IsAssignableToVisitor(source))) {
355 return false;
356 }
357 }
358 hasLowerBounds = true;
359 }
360 if (hasUpperBounds) {
361 return this.wildcard.getLowerBounds().isEmpty();
362 } else if (hasLowerBounds) {
363 TypeList.Generic upperBounds = this.wildcard.getUpperBounds();
364 return upperBounds.size() == 0 || upperBounds.size() == 1 && upperBounds.getOnly().represents(Object.class);
365 } else {
366 return true;
367 }
368 }
369
370
373 public Boolean onParameterizedType(TypeDescription.Generic parameterizedType) {
374 return false;
375 }
376
377
380 public Boolean onTypeVariable(TypeDescription.Generic typeVariable) {
381 return false;
382 }
383
384
387 public Boolean onNonGenericType(TypeDescription.Generic typeDescription) {
388 return false;
389 }
390 }
391
392
395 protected static class OfParameterizedType extends OfSimpleType {
396
397
403 protected OfParameterizedType(TypeDescription.Generic typeDescription, boolean polymorphic) {
404 super(typeDescription, polymorphic);
405 }
406
407
410 public Boolean onGenericArray(TypeDescription.Generic genericArray) {
411 return false;
412 }
413 }
414
415
418 protected static class OfNonGenericType extends OfSimpleType {
419
420
426 protected OfNonGenericType(TypeDescription.Generic typeDescription, boolean polymorphic) {
427 super(typeDescription, polymorphic);
428 }
429
430
433 public Boolean onGenericArray(TypeDescription.Generic genericArray) {
434 return polymorphic
435 ? typeDescription.asErasure().isAssignableTo(genericArray.asErasure())
436 : typeDescription.asErasure().equals(genericArray.asErasure());
437 }
438 }
439 }
440 }
441