1 /*
2 * Copyright 2014 - 2020 Rafael Winterhalter
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package net.bytebuddy.dynamic.scaffold;
17
18 import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19 import net.bytebuddy.ClassFileVersion;
20 import net.bytebuddy.asm.AsmVisitorWrapper;
21 import net.bytebuddy.build.HashCodeAndEqualsPlugin;
22 import net.bytebuddy.description.annotation.AnnotationList;
23 import net.bytebuddy.description.annotation.AnnotationValue;
24 import net.bytebuddy.description.field.FieldDescription;
25 import net.bytebuddy.description.field.FieldList;
26 import net.bytebuddy.description.method.MethodDescription;
27 import net.bytebuddy.description.method.MethodList;
28 import net.bytebuddy.description.method.ParameterDescription;
29 import net.bytebuddy.description.method.ParameterList;
30 import net.bytebuddy.description.modifier.ModifierContributor;
31 import net.bytebuddy.description.modifier.Visibility;
32 import net.bytebuddy.description.type.*;
33 import net.bytebuddy.dynamic.ClassFileLocator;
34 import net.bytebuddy.dynamic.DynamicType;
35 import net.bytebuddy.dynamic.TypeResolutionStrategy;
36 import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
37 import net.bytebuddy.dynamic.scaffold.inline.RebaseImplementationTarget;
38 import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget;
39 import net.bytebuddy.implementation.Implementation;
40 import net.bytebuddy.implementation.LoadedTypeInitializer;
41 import net.bytebuddy.implementation.attribute.*;
42 import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
43 import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
44 import net.bytebuddy.implementation.bytecode.StackManipulation;
45 import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
46 import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
47 import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
48 import net.bytebuddy.implementation.bytecode.member.MethodReturn;
49 import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
50 import net.bytebuddy.pool.TypePool;
51 import net.bytebuddy.utility.CompoundList;
52 import net.bytebuddy.utility.OpenedClassReader;
53 import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
54 import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
55 import net.bytebuddy.jar.asm.*;
56 import net.bytebuddy.jar.asm.commons.ClassRemapper;
57 import net.bytebuddy.jar.asm.commons.Remapper;
58 import net.bytebuddy.jar.asm.commons.SimpleRemapper;
59
60 import java.io.File;
61 import java.io.FileOutputStream;
62 import java.io.IOException;
63 import java.io.OutputStream;
64 import java.security.AccessController;
65 import java.security.PrivilegedExceptionAction;
66 import java.util.*;
67
68 import static net.bytebuddy.matcher.ElementMatchers.*;
69
70 /**
71 * A type writer is a utility for writing an actual class file using the ASM library.
72 *
73 * @param <T> The best known loaded type for the dynamically created type.
74 */
75 public interface TypeWriter<T> {
76
77 /**
78 * A system property that indicates a folder for Byte Buddy to dump class files of all types that it creates.
79 * If this property is not set, Byte Buddy does not dump any class files. This property is only read a single
80 * time which is why it must be set on application start-up.
81 */
82 String DUMP_PROPERTY = "net.bytebuddy.dump";
83
84 /**
85 * Creates the dynamic type that is described by this type writer.
86 *
87 * @param typeResolver The type resolution strategy to use.
88 * @return An unloaded dynamic type that describes the created type.
89 */
90 DynamicType.Unloaded<T> make(TypeResolutionStrategy.Resolved typeResolver);
91
92 /**
93 * An field pool that allows a lookup for how to implement a field.
94 */
95 interface FieldPool {
96
97 /**
98 * Looks up a handler entry for a given field.
99 *
100 * @param fieldDescription The field being processed.
101 * @return A handler entry for the given field.
102 */
103 Record target(FieldDescription fieldDescription);
104
105 /**
106 * An entry of a field pool that describes how a field is implemented.
107 *
108 * @see net.bytebuddy.dynamic.scaffold.TypeWriter.FieldPool
109 */
110 interface Record {
111
112 /**
113 * Determines if this record is implicit, i.e is not defined by a {@link FieldPool}.
114 *
115 * @return {@code true} if this record is implicit.
116 */
117 boolean isImplicit();
118
119 /**
120 * Returns the field that this record represents.
121 *
122 * @return The field that this record represents.
123 */
124 FieldDescription getField();
125
126 /**
127 * Returns the field attribute appender for a given field.
128 *
129 * @return The attribute appender to be applied on the given field.
130 */
131 FieldAttributeAppender getFieldAppender();
132
133 /**
134 * Resolves the default value that this record represents. This is not possible for implicit records.
135 *
136 * @param defaultValue The default value that was defined previously or {@code null} if no default value is defined.
137 * @return The default value for the represented field or {@code null} if no default value is to be defined.
138 */
139 Object resolveDefault(Object defaultValue);
140
141 /**
142 * Writes this entry to a given class visitor.
143 *
144 * @param classVisitor The class visitor to which this entry is to be written to.
145 * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
146 */
147 void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
148
149 /**
150 * Applies this record to a field visitor. This is not possible for implicit records.
151 *
152 * @param fieldVisitor The field visitor onto which this record is to be applied.
153 * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
154 */
155 void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
156
157 /**
158 * A record for a simple field without a default value where all of the field's declared annotations are appended.
159 */
160 @HashCodeAndEqualsPlugin.Enhance
161 class ForImplicitField implements Record {
162
163 /**
164 * The implemented field.
165 */
166 private final FieldDescription fieldDescription;
167
168 /**
169 * Creates a new record for a simple field.
170 *
171 * @param fieldDescription The described field.
172 */
173 public ForImplicitField(FieldDescription fieldDescription) {
174 this.fieldDescription = fieldDescription;
175 }
176
177 /**
178 * {@inheritDoc}
179 */
180 public boolean isImplicit() {
181 return true;
182 }
183
184 /**
185 * {@inheritDoc}
186 */
187 public FieldDescription getField() {
188 return fieldDescription;
189 }
190
191 /**
192 * {@inheritDoc}
193 */
194 public FieldAttributeAppender getFieldAppender() {
195 throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
196 }
197
198 /**
199 * {@inheritDoc}
200 */
201 public Object resolveDefault(Object defaultValue) {
202 throw new IllegalStateException("An implicit field record does not expose a default value: " + this);
203 }
204
205 /**
206 * {@inheritDoc}
207 */
208 public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
209 FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
210 fieldDescription.getInternalName(),
211 fieldDescription.getDescriptor(),
212 fieldDescription.getGenericSignature(),
213 FieldDescription.NO_DEFAULT_VALUE);
214 if (fieldVisitor != null) {
215 FieldAttributeAppender.ForInstrumentedField.INSTANCE.apply(fieldVisitor,
216 fieldDescription,
217 annotationValueFilterFactory.on(fieldDescription));
218 fieldVisitor.visitEnd();
219 }
220 }
221
222 /**
223 * {@inheritDoc}
224 */
225 public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
226 throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
227 }
228 }
229
230 /**
231 * A record for a rich field with attributes and a potential default value.
232 */
233 @HashCodeAndEqualsPlugin.Enhance
234 class ForExplicitField implements Record {
235
236 /**
237 * The attribute appender for the field.
238 */
239 private final FieldAttributeAppender attributeAppender;
240
241 /**
242 * The field's default value.
243 */
244 private final Object defaultValue;
245
246 /**
247 * The implemented field.
248 */
249 private final FieldDescription fieldDescription;
250
251 /**
252 * Creates a record for a rich field.
253 *
254 * @param attributeAppender The attribute appender for the field.
255 * @param defaultValue The field's default value.
256 * @param fieldDescription The implemented field.
257 */
258 public ForExplicitField(FieldAttributeAppender attributeAppender, Object defaultValue, FieldDescription fieldDescription) {
259 this.attributeAppender = attributeAppender;
260 this.defaultValue = defaultValue;
261 this.fieldDescription = fieldDescription;
262 }
263
264 /**
265 * {@inheritDoc}
266 */
267 public boolean isImplicit() {
268 return false;
269 }
270
271 /**
272 * {@inheritDoc}
273 */
274 public FieldDescription getField() {
275 return fieldDescription;
276 }
277
278 /**
279 * {@inheritDoc}
280 */
281 public FieldAttributeAppender getFieldAppender() {
282 return attributeAppender;
283 }
284
285 /**
286 * {@inheritDoc}
287 */
288 public Object resolveDefault(Object defaultValue) {
289 return this.defaultValue == null
290 ? defaultValue
291 : this.defaultValue;
292 }
293
294 /**
295 * {@inheritDoc}
296 */
297 public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
298 FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
299 fieldDescription.getInternalName(),
300 fieldDescription.getDescriptor(),
301 fieldDescription.getGenericSignature(),
302 resolveDefault(FieldDescription.NO_DEFAULT_VALUE));
303 if (fieldVisitor != null) {
304 attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
305 fieldVisitor.visitEnd();
306 }
307 }
308
309 /**
310 * {@inheritDoc}
311 */
312 public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
313 attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
314 }
315 }
316 }
317
318 /**
319 * A field pool that does not allow any look ups.
320 */
321 enum Disabled implements FieldPool {
322
323 /**
324 * The singleton instance.
325 */
326 INSTANCE;
327
328 /**
329 * {@inheritDoc}
330 */
331 public Record target(FieldDescription fieldDescription) {
332 throw new IllegalStateException("Cannot look up field from disabled pool");
333 }
334 }
335 }
336
337 /**
338 * An method pool that allows a lookup for how to implement a method.
339 */
340 interface MethodPool {
341
342 /**
343 * Looks up a handler entry for a given method.
344 *
345 * @param methodDescription The method being processed.
346 * @return A handler entry for the given method.
347 */
348 Record target(MethodDescription methodDescription);
349
350 /**
351 * An entry of a method pool that describes how a method is implemented.
352 *
353 * @see net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool
354 */
355 interface Record {
356
357 /**
358 * Returns the sort of this method instrumentation.
359 *
360 * @return The sort of this method instrumentation.
361 */
362 Sort getSort();
363
364 /**
365 * Returns the method that is implemented where the returned method resembles a potential transformation. An implemented
366 * method is only defined if a method is not {@link Record.Sort#SKIPPED}.
367 *
368 * @return The implemented method.
369 */
370 MethodDescription getMethod();
371
372 /**
373 * The visibility to enforce for this method.
374 *
375 * @return The visibility to enforce for this method.
376 */
377 Visibility getVisibility();
378
379 /**
380 * Prepends the given method appender to this entry.
381 *
382 * @param byteCodeAppender The byte code appender to prepend.
383 * @return This entry with the given code prepended.
384 */
385 Record prepend(ByteCodeAppender byteCodeAppender);
386
387 /**
388 * Applies this method entry. This method can always be called and might be a no-op.
389 *
390 * @param classVisitor The class visitor to which this entry should be applied.
391 * @param implementationContext The implementation context to which this entry should be applied.
392 * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
393 */
394 void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
395
396 /**
397 * Applies the head of this entry. Applying an entry is only possible if a method is defined, i.e. the sort of this entry is not
398 * {@link Record.Sort#SKIPPED}.
399 *
400 * @param methodVisitor The method visitor to which this entry should be applied.
401 */
402 void applyHead(MethodVisitor methodVisitor);
403
404 /**
405 * Applies the body of this entry. Applying the body of an entry is only possible if a method is implemented, i.e. the sort of this
406 * entry is {@link Record.Sort#IMPLEMENTED}.
407 *
408 * @param methodVisitor The method visitor to which this entry should be applied.
409 * @param implementationContext The implementation context to which this entry should be applied.
410 * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
411 */
412 void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
413
414 /**
415 * Applies the attributes of this entry. Applying the body of an entry is only possible if a method is implemented, i.e. the sort of this
416 * entry is {@link Record.Sort#DEFINED}.
417 *
418 * @param methodVisitor The method visitor to which this entry should be applied.
419 * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
420 */
421 void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
422
423 /**
424 * Applies the code of this entry. Applying the body of an entry is only possible if a method is implemented, i.e. the sort of this
425 * entry is {@link Record.Sort#IMPLEMENTED}.
426 *
427 * @param methodVisitor The method visitor to which this entry should be applied.
428 * @param implementationContext The implementation context to which this entry should be applied.
429 * @return The size requirements of the implemented code.
430 */
431 ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext);
432
433 /**
434 * The sort of an entry.
435 */
436 enum Sort {
437
438 /**
439 * Describes a method that should not be implemented or retained in its original state.
440 */
441 SKIPPED(false, false),
442
443 /**
444 * Describes a method that should be defined but is abstract or native, i.e. does not define any byte code.
445 */
446 DEFINED(true, false),
447
448 /**
449 * Describes a method that is implemented in byte code.
450 */
451 IMPLEMENTED(true, true);
452
453 /**
454 * Indicates if this sort defines a method, with or without byte code.
455 */
456 private final boolean define;
457
458 /**
459 * Indicates if this sort defines byte code.
460 */
461 private final boolean implement;
462
463 /**
464 * Creates a new sort.
465 *
466 * @param define Indicates if this sort defines a method, with or without byte code.
467 * @param implement Indicates if this sort defines byte code.
468 */
469 Sort(boolean define, boolean implement) {
470 this.define = define;
471 this.implement = implement;
472 }
473
474 /**
475 * Indicates if this sort defines a method, with or without byte code.
476 *
477 * @return {@code true} if this sort defines a method, with or without byte code.
478 */
479 public boolean isDefined() {
480 return define;
481 }
482
483 /**
484 * Indicates if this sort defines byte code.
485 *
486 * @return {@code true} if this sort defines byte code.
487 */
488 public boolean isImplemented() {
489 return implement;
490 }
491 }
492
493 /**
494 * A canonical implementation of a method that is not declared but inherited by the instrumented type.
495 */
496 @HashCodeAndEqualsPlugin.Enhance
497 class ForNonImplementedMethod implements Record {
498
499 /**
500 * The undefined method.
501 */
502 private final MethodDescription methodDescription;
503
504 /**
505 * Creates a new undefined record.
506 *
507 * @param methodDescription The undefined method.
508 */
509 public ForNonImplementedMethod(MethodDescription methodDescription) {
510 this.methodDescription = methodDescription;
511 }
512
513 /**
514 * {@inheritDoc}
515 */
516 public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
517 /* do nothing */
518 }
519
520 /**
521 * {@inheritDoc}
522 */
523 public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
524 throw new IllegalStateException("Cannot apply body for non-implemented method on " + methodDescription);
525 }
526
527 /**
528 * {@inheritDoc}
529 */
530 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
531 /* do nothing */
532 }
533
534 /**
535 * {@inheritDoc}
536 */
537 public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
538 throw new IllegalStateException("Cannot apply code for non-implemented method on " + methodDescription);
539 }
540
541 /**
542 * {@inheritDoc}
543 */
544 public void applyHead(MethodVisitor methodVisitor) {
545 throw new IllegalStateException("Cannot apply head for non-implemented method on " + methodDescription);
546 }
547
548 /**
549 * {@inheritDoc}
550 */
551 public MethodDescription getMethod() {
552 return methodDescription;
553 }
554
555 /**
556 * {@inheritDoc}
557 */
558 public Visibility getVisibility() {
559 return methodDescription.getVisibility();
560 }
561
562 /**
563 * {@inheritDoc}
564 */
565 public Sort getSort() {
566 return Sort.SKIPPED;
567 }
568
569 /**
570 * {@inheritDoc}
571 */
572 public Record prepend(ByteCodeAppender byteCodeAppender) {
573 return new ForDefinedMethod.WithBody(methodDescription, new ByteCodeAppender.Compound(byteCodeAppender,
574 new ByteCodeAppender.Simple(DefaultValue.of(methodDescription.getReturnType()), MethodReturn.of(methodDescription.getReturnType()))));
575 }
576 }
577
578 /**
579 * A base implementation of an abstract entry that defines a method.
580 */
581 abstract class ForDefinedMethod implements Record {
582
583 /**
584 * {@inheritDoc}
585 */
586 public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
587 MethodVisitor methodVisitor = classVisitor.visitMethod(getMethod().getActualModifiers(getSort().isImplemented(), getVisibility()),
588 getMethod().getInternalName(),
589 getMethod().getDescriptor(),
590 getMethod().getGenericSignature(),
591 getMethod().getExceptionTypes().asErasures().toInternalNames());
592 if (methodVisitor != null) {
593 ParameterList<?> parameterList = getMethod().getParameters();
594 if (parameterList.hasExplicitMetaData()) {
595 for (ParameterDescription parameterDescription : parameterList) {
596 methodVisitor.visitParameter(parameterDescription.getName(), parameterDescription.getModifiers());
597 }
598 }
599 applyHead(methodVisitor);
600 applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
601 methodVisitor.visitEnd();
602 }
603 }
604
605 /**
606 * Describes an entry that defines a method as byte code.
607 */
608 @HashCodeAndEqualsPlugin.Enhance
609 public static class WithBody extends ForDefinedMethod {
610
611 /**
612 * The implemented method.
613 */
614 private final MethodDescription methodDescription;
615
616 /**
617 * The byte code appender to apply.
618 */
619 private final ByteCodeAppender byteCodeAppender;
620
621 /**
622 * The method attribute appender to apply.
623 */
624 private final MethodAttributeAppender methodAttributeAppender;
625
626 /**
627 * The represented method's minimum visibility.
628 */
629 private final Visibility visibility;
630
631 /**
632 * Creates a new record for an implemented method without attributes or a modifier resolver.
633 *
634 * @param methodDescription The implemented method.
635 * @param byteCodeAppender The byte code appender to apply.
636 */
637 public WithBody(MethodDescription methodDescription, ByteCodeAppender byteCodeAppender) {
638 this(methodDescription, byteCodeAppender, MethodAttributeAppender.NoOp.INSTANCE, methodDescription.getVisibility());
639 }
640
641 /**
642 * Creates a new entry for a method that defines a method as byte code.
643 *
644 * @param methodDescription The implemented method.
645 * @param byteCodeAppender The byte code appender to apply.
646 * @param methodAttributeAppender The method attribute appender to apply.
647 * @param visibility The represented method's minimum visibility.
648 */
649 public WithBody(MethodDescription methodDescription,
650 ByteCodeAppender byteCodeAppender,
651 MethodAttributeAppender methodAttributeAppender,
652 Visibility visibility) {
653 this.methodDescription = methodDescription;
654 this.byteCodeAppender = byteCodeAppender;
655 this.methodAttributeAppender = methodAttributeAppender;
656 this.visibility = visibility;
657 }
658
659 /**
660 * {@inheritDoc}
661 */
662 public MethodDescription getMethod() {
663 return methodDescription;
664 }
665
666 /**
667 * {@inheritDoc}
668 */
669 public Sort getSort() {
670 return Sort.IMPLEMENTED;
671 }
672
673 /**
674 * {@inheritDoc}
675 */
676 public Visibility getVisibility() {
677 return visibility;
678 }
679
680 /**
681 * {@inheritDoc}
682 */
683 public void applyHead(MethodVisitor methodVisitor) {
684 /* do nothing */
685 }
686
687 /**
688 * {@inheritDoc}
689 */
690 public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
691 applyAttributes(methodVisitor, annotationValueFilterFactory);
692 methodVisitor.visitCode();
693 ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
694 methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
695 }
696
697 /**
698 * {@inheritDoc}
699 */
700 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
701 methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
702 }
703
704 /**
705 * {@inheritDoc}
706 */
707 public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
708 return byteCodeAppender.apply(methodVisitor, implementationContext, methodDescription);
709 }
710
711 /**
712 * {@inheritDoc}
713 */
714 public Record prepend(ByteCodeAppender byteCodeAppender) {
715 return new WithBody(methodDescription,
716 new ByteCodeAppender.Compound(byteCodeAppender, this.byteCodeAppender),
717 methodAttributeAppender,
718 visibility);
719 }
720 }
721
722 /**
723 * Describes an entry that defines a method but without byte code and without an annotation value.
724 */
725 @HashCodeAndEqualsPlugin.Enhance
726 public static class WithoutBody extends ForDefinedMethod {
727
728 /**
729 * The implemented method.
730 */
731 private final MethodDescription methodDescription;
732
733 /**
734 * The method attribute appender to apply.
735 */
736 private final MethodAttributeAppender methodAttributeAppender;
737
738 /**
739 * The represented method's minimum visibility.
740 */
741 private final Visibility visibility;
742
743 /**
744 * Creates a new entry for a method that is defines but does not append byte code, i.e. is native or abstract.
745 *
746 * @param methodDescription The implemented method.
747 * @param methodAttributeAppender The method attribute appender to apply.
748 * @param visibility The represented method's minimum visibility.
749 */
750 public WithoutBody(MethodDescription methodDescription, MethodAttributeAppender methodAttributeAppender, Visibility visibility) {
751 this.methodDescription = methodDescription;
752 this.methodAttributeAppender = methodAttributeAppender;
753 this.visibility = visibility;
754 }
755
756 /**
757 * {@inheritDoc}
758 */
759 public MethodDescription getMethod() {
760 return methodDescription;
761 }
762
763 /**
764 * {@inheritDoc}
765 */
766 public Sort getSort() {
767 return Sort.DEFINED;
768 }
769
770 /**
771 * {@inheritDoc}
772 */
773 public Visibility getVisibility() {
774 return visibility;
775 }
776
777 /**
778 * {@inheritDoc}
779 */
780 public void applyHead(MethodVisitor methodVisitor) {
781 /* do nothing */
782 }
783
784 /**
785 * {@inheritDoc}
786 */
787 public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
788 applyAttributes(methodVisitor, annotationValueFilterFactory);
789 }
790
791 /**
792 * {@inheritDoc}
793 */
794 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
795 methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
796 }
797
798 /**
799 * {@inheritDoc}
800 */
801 public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
802 throw new IllegalStateException("Cannot apply code for abstract method on " + methodDescription);
803 }
804
805 /**
806 * {@inheritDoc}
807 */
808 public Record prepend(ByteCodeAppender byteCodeAppender) {
809 throw new IllegalStateException("Cannot prepend code for abstract method on " + methodDescription);
810 }
811 }
812
813 /**
814 * Describes an entry that defines a method with a default annotation value.
815 */
816 @HashCodeAndEqualsPlugin.Enhance
817 public static class WithAnnotationDefaultValue extends ForDefinedMethod {
818
819 /**
820 * The implemented method.
821 */
822 private final MethodDescription methodDescription;
823
824 /**
825 * The annotation value to define.
826 */
827 private final AnnotationValue<?, ?> annotationValue;
828
829 /**
830 * The method attribute appender to apply.
831 */
832 private final MethodAttributeAppender methodAttributeAppender;
833
834 /**
835 * Creates a new entry for defining a method with a default annotation value.
836 *
837 * @param methodDescription The implemented method.
838 * @param annotationValue The annotation value to define.
839 * @param methodAttributeAppender The method attribute appender to apply.
840 */
841 public WithAnnotationDefaultValue(MethodDescription methodDescription,
842 AnnotationValue<?, ?> annotationValue,
843 MethodAttributeAppender methodAttributeAppender) {
844 this.methodDescription = methodDescription;
845 this.annotationValue = annotationValue;
846 this.methodAttributeAppender = methodAttributeAppender;
847 }
848
849 /**
850 * {@inheritDoc}
851 */
852 public MethodDescription getMethod() {
853 return methodDescription;
854 }
855
856 /**
857 * {@inheritDoc}
858 */
859 public Sort getSort() {
860 return Sort.DEFINED;
861 }
862
863 /**
864 * {@inheritDoc}
865 */
866 public Visibility getVisibility() {
867 return methodDescription.getVisibility();
868 }
869
870 /**
871 * {@inheritDoc}
872 */
873 public void applyHead(MethodVisitor methodVisitor) {
874 if (!methodDescription.isDefaultValue(annotationValue)) {
875 throw new IllegalStateException("Cannot set " + annotationValue + " as default for " + methodDescription);
876 }
877 AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
878 AnnotationAppender.Default.apply(annotationVisitor,
879 methodDescription.getReturnType().asErasure(),
880 AnnotationAppender.NO_NAME,
881 annotationValue.resolve());
882 annotationVisitor.visitEnd();
883 }
884
885 /**
886 * {@inheritDoc}
887 */
888 public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
889 methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
890 }
891
892 /**
893 * {@inheritDoc}
894 */
895 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
896 throw new IllegalStateException("Cannot apply attributes for default value on " + methodDescription);
897 }
898
899 /**
900 * {@inheritDoc}
901 */
902 public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
903 throw new IllegalStateException("Cannot apply code for default value on " + methodDescription);
904 }
905
906 /**
907 * {@inheritDoc}
908 */
909 public Record prepend(ByteCodeAppender byteCodeAppender) {
910 throw new IllegalStateException("Cannot prepend code for default value on " + methodDescription);
911 }
912 }
913
914 /**
915 * A record for a visibility bridge.
916 */
917 @HashCodeAndEqualsPlugin.Enhance
918 public static class OfVisibilityBridge extends ForDefinedMethod implements ByteCodeAppender {
919
920 /**
921 * The visibility bridge.
922 */
923 private final MethodDescription visibilityBridge;
924
925 /**
926 * The method the visibility bridge invokes.
927 */
928 private final MethodDescription bridgeTarget;
929
930 /**
931 * The type on which the bridge method is invoked.
932 */
933 private final TypeDescription bridgeType;
934
935 /**
936 * The attribute appender to apply to the visibility bridge.
937 */
938 private final MethodAttributeAppender attributeAppender;
939
940 /**
941 * Creates a new record for a visibility bridge.
942 *
943 * @param visibilityBridge The visibility bridge.
944 * @param bridgeTarget The method the visibility bridge invokes.
945 * @param bridgeType The type of the instrumented type.
946 * @param attributeAppender The attribute appender to apply to the visibility bridge.
947 */
948 protected OfVisibilityBridge(MethodDescription visibilityBridge,
949 MethodDescription bridgeTarget,
950 TypeDescription bridgeType,
951 MethodAttributeAppender attributeAppender) {
952 this.visibilityBridge = visibilityBridge;
953 this.bridgeTarget = bridgeTarget;
954 this.bridgeType = bridgeType;
955 this.attributeAppender = attributeAppender;
956 }
957
958 /**
959 * Creates a record for a visibility bridge.
960 *
961 * @param instrumentedType The instrumented type.
962 * @param bridgeTarget The target method of the visibility bridge.
963 * @param attributeAppender The attribute appender to apply to the visibility bridge.
964 * @return A record describing the visibility bridge.
965 */
966 public static Record of(TypeDescription instrumentedType, MethodDescription bridgeTarget, MethodAttributeAppender attributeAppender) {
967 // Default method bridges must be dispatched on an implemented interface type, not considering the declaring type.
968 TypeDefinition bridgeType = null;
969 if (bridgeTarget.isDefaultMethod()) {
970 TypeDescription declaringType = bridgeTarget.getDeclaringType().asErasure();
971 for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures().filter(isSubTypeOf(declaringType))) {
972 if (bridgeType == null || declaringType.isAssignableTo(bridgeType.asErasure())) {
973 bridgeType = interfaceType;
974 }
975 }
976 }
977 // Non-default method or default method that is inherited by a super class.
978 if (bridgeType == null) {
979 bridgeType = instrumentedType.getSuperClass();
980 }
981 return new OfVisibilityBridge(new VisibilityBridge(instrumentedType, bridgeTarget),
982 bridgeTarget,
983 bridgeType.asErasure(),
984 attributeAppender);
985 }
986
987 /**
988 * {@inheritDoc}
989 */
990 public MethodDescription getMethod() {
991 return visibilityBridge;
992 }
993
994 /**
995 * {@inheritDoc}
996 */
997 public Sort getSort() {
998 return Sort.IMPLEMENTED;
999 }
1000
1001 /**
1002 * {@inheritDoc}
1003 */
1004 public Visibility getVisibility() {
1005 return bridgeTarget.getVisibility();
1006 }
1007
1008 /**
1009 * {@inheritDoc}
1010 */
1011 public Record prepend(ByteCodeAppender byteCodeAppender) {
1012 return new ForDefinedMethod.WithBody(visibilityBridge,
1013 new ByteCodeAppender.Compound(this, byteCodeAppender),
1014 attributeAppender,
1015 bridgeTarget.getVisibility());
1016 }
1017
1018 /**
1019 * {@inheritDoc}
1020 */
1021 public void applyHead(MethodVisitor methodVisitor) {
1022 /* do nothing */
1023 }
1024
1025 /**
1026 * {@inheritDoc}
1027 */
1028 public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1029 applyAttributes(methodVisitor, annotationValueFilterFactory);
1030 methodVisitor.visitCode();
1031 ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1032 methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1033 }
1034
1035 /**
1036 * {@inheritDoc}
1037 */
1038 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1039 attributeAppender.apply(methodVisitor, visibilityBridge, annotationValueFilterFactory.on(visibilityBridge));
1040 }
1041
1042 /**
1043 * {@inheritDoc}
1044 */
1045 public Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1046 return apply(methodVisitor, implementationContext, visibilityBridge);
1047 }
1048
1049 /**
1050 * {@inheritDoc}
1051 */
1052 public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1053 return new ByteCodeAppender.Simple(
1054 MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1055 MethodInvocation.invoke(bridgeTarget).special(bridgeType),
1056 MethodReturn.of(instrumentedMethod.getReturnType())
1057 ).apply(methodVisitor, implementationContext, instrumentedMethod);
1058 }
1059
1060 /**
1061 * A method describing a visibility bridge.
1062 */
1063 protected static class VisibilityBridge extends MethodDescription.InDefinedShape.AbstractBase {
1064
1065 /**
1066 * The instrumented type.
1067 */
1068 private final TypeDescription instrumentedType;
1069
1070 /**
1071 * The method that is the target of the bridge.
1072 */
1073 private final MethodDescription bridgeTarget;
1074
1075 /**
1076 * Creates a new visibility bridge.
1077 *
1078 * @param instrumentedType The instrumented type.
1079 * @param bridgeTarget The method that is the target of the bridge.
1080 */
1081 protected VisibilityBridge(TypeDescription instrumentedType, MethodDescription bridgeTarget) {
1082 this.instrumentedType = instrumentedType;
1083 this.bridgeTarget = bridgeTarget;
1084 }
1085
1086 /**
1087 * {@inheritDoc}
1088 */
1089 public TypeDescription getDeclaringType() {
1090 return instrumentedType;
1091 }
1092
1093 /**
1094 * {@inheritDoc}
1095 */
1096 public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1097 return new ParameterList.Explicit.ForTypes(this, bridgeTarget.getParameters().asTypeList().asRawTypes());
1098 }
1099
1100 /**
1101 * {@inheritDoc}
1102 */
1103 public TypeDescription.Generic getReturnType() {
1104 return bridgeTarget.getReturnType().asRawType();
1105 }
1106
1107 /**
1108 * {@inheritDoc}
1109 */
1110 public TypeList.Generic getExceptionTypes() {
1111 return bridgeTarget.getExceptionTypes().asRawTypes();
1112 }
1113
1114 /**
1115 * {@inheritDoc}
1116 */
1117 public AnnotationValue<?, ?> getDefaultValue() {
1118 return AnnotationValue.UNDEFINED;
1119 }
1120
1121 /**
1122 * {@inheritDoc}
1123 */
1124 public TypeList.Generic getTypeVariables() {
1125 return new TypeList.Generic.Empty();
1126 }
1127
1128 /**
1129 * {@inheritDoc}
1130 */
1131 public AnnotationList getDeclaredAnnotations() {
1132 return bridgeTarget.getDeclaredAnnotations();
1133 }
1134
1135 /**
1136 * {@inheritDoc}
1137 */
1138 public int getModifiers() {
1139 return (bridgeTarget.getModifiers() | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE) & ~Opcodes.ACC_NATIVE;
1140 }
1141
1142 /**
1143 * {@inheritDoc}
1144 */
1145 public String getInternalName() {
1146 return bridgeTarget.getName();
1147 }
1148 }
1149 }
1150 }
1151
1152 /**
1153 * A wrapper that appends accessor bridges for a method's implementation. The bridges are only added if
1154 * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool.Record#apply(ClassVisitor, Implementation.Context, AnnotationValueFilter.Factory)}
1155 * is invoked such that bridges are not appended for methods that are rebased or redefined as such types already have bridge methods in place.
1156 */
1157 @HashCodeAndEqualsPlugin.Enhance
1158 class AccessBridgeWrapper implements Record {
1159
1160 /**
1161 * The delegate for implementing the bridge's target.
1162 */
1163 private final Record delegate;
1164
1165 /**
1166 * The instrumented type that defines the bridge methods and the bridge target.
1167 */
1168 private final TypeDescription instrumentedType;
1169
1170 /**
1171 * The target of the bridge method.
1172 */
1173 private final MethodDescription bridgeTarget;
1174
1175 /**
1176 * A collection of all tokens representing all bridge methods.
1177 */
1178 private final Set<MethodDescription.TypeToken> bridgeTypes;
1179
1180 /**
1181 * The attribute appender being applied for the bridge target.
1182 */
1183 private final MethodAttributeAppender attributeAppender;
1184
1185 /**
1186 * Creates a wrapper for adding accessor bridges.
1187 *
1188 * @param delegate The delegate for implementing the bridge's target.
1189 * @param instrumentedType The instrumented type that defines the bridge methods and the bridge target.
1190 * @param bridgeTarget The target of the bridge method.
1191 * @param bridgeTypes A collection of all tokens representing all bridge methods.
1192 * @param attributeAppender The attribute appender being applied for the bridge target.
1193 */
1194 protected AccessBridgeWrapper(Record delegate,
1195 TypeDescription instrumentedType,
1196 MethodDescription bridgeTarget,
1197 Set<MethodDescription.TypeToken> bridgeTypes,
1198 MethodAttributeAppender attributeAppender) {
1199 this.delegate = delegate;
1200 this.instrumentedType = instrumentedType;
1201 this.bridgeTarget = bridgeTarget;
1202 this.bridgeTypes = bridgeTypes;
1203 this.attributeAppender = attributeAppender;
1204 }
1205
1206 /**
1207 * Wraps the given record in an accessor bridge wrapper if necessary.
1208 *
1209 * @param delegate The delegate for implementing the bridge's target.
1210 * @param instrumentedType The instrumented type that defines the bridge methods and the bridge target.
1211 * @param bridgeTarget The bridge methods' target methods.
1212 * @param bridgeTypes A collection of all tokens representing all bridge methods.
1213 * @param attributeAppender The attribute appender being applied for the bridge target.
1214 * @return The given record wrapped by a bridge method wrapper if necessary.
1215 */
1216 public static Record of(Record delegate,
1217 TypeDescription instrumentedType,
1218 MethodDescription bridgeTarget,
1219 Set<MethodDescription.TypeToken> bridgeTypes,
1220 MethodAttributeAppender attributeAppender) {
1221 Set<MethodDescription.TypeToken> compatibleBridgeTypes = new HashSet<MethodDescription.TypeToken>();
1222 for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1223 if (bridgeTarget.isBridgeCompatible(bridgeType)) {
1224 compatibleBridgeTypes.add(bridgeType);
1225 }
1226 }
1227 return compatibleBridgeTypes.isEmpty() || (instrumentedType.isInterface() && !delegate.getSort().isImplemented())
1228 ? delegate
1229 : new AccessBridgeWrapper(delegate, instrumentedType, bridgeTarget, compatibleBridgeTypes, attributeAppender);
1230 }
1231
1232 /**
1233 * {@inheritDoc}
1234 */
1235 public Sort getSort() {
1236 return delegate.getSort();
1237 }
1238
1239 /**
1240 * {@inheritDoc}
1241 */
1242 public MethodDescription getMethod() {
1243 return bridgeTarget;
1244 }
1245
1246 /**
1247 * {@inheritDoc}
1248 */
1249 public Visibility getVisibility() {
1250 return delegate.getVisibility();
1251 }
1252
1253 /**
1254 * {@inheritDoc}
1255 */
1256 public Record prepend(ByteCodeAppender byteCodeAppender) {
1257 return new AccessBridgeWrapper(delegate.prepend(byteCodeAppender), instrumentedType, bridgeTarget, bridgeTypes, attributeAppender);
1258 }
1259
1260 /**
1261 * {@inheritDoc}
1262 */
1263 public void apply(ClassVisitor classVisitor,
1264 Implementation.Context implementationContext,
1265 AnnotationValueFilter.Factory annotationValueFilterFactory) {
1266 delegate.apply(classVisitor, implementationContext, annotationValueFilterFactory);
1267 for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1268 MethodDescription.InDefinedShape bridgeMethod = new AccessorBridge(bridgeTarget, bridgeType, instrumentedType);
1269 MethodDescription.InDefinedShape bridgeTarget = new BridgeTarget(this.bridgeTarget, instrumentedType);
1270 MethodVisitor methodVisitor = classVisitor.visitMethod(bridgeMethod.getActualModifiers(true, getVisibility()),
1271 bridgeMethod.getInternalName(),
1272 bridgeMethod.getDescriptor(),
1273 MethodDescription.NON_GENERIC_SIGNATURE,
1274 bridgeMethod.getExceptionTypes().asErasures().toInternalNames());
1275 if (methodVisitor != null) {
1276 attributeAppender.apply(methodVisitor, bridgeMethod, annotationValueFilterFactory.on(instrumentedType));
1277 methodVisitor.visitCode();
1278 ByteCodeAppender.Size size = new ByteCodeAppender.Simple(
1279 MethodVariableAccess.allArgumentsOf(bridgeMethod).asBridgeOf(bridgeTarget).prependThisReference(),
1280 MethodInvocation.invoke(bridgeTarget).virtual(instrumentedType),
1281 bridgeTarget.getReturnType().asErasure().isAssignableTo(bridgeMethod.getReturnType().asErasure())
1282 ? StackManipulation.Trivial.INSTANCE
1283 : TypeCasting.to(bridgeMethod.getReturnType().asErasure()),
1284 MethodReturn.of(bridgeMethod.getReturnType())
1285 ).apply(methodVisitor, implementationContext, bridgeMethod);
1286 methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1287 methodVisitor.visitEnd();
1288 }
1289 }
1290 }
1291
1292 /**
1293 * {@inheritDoc}
1294 */
1295 public void applyHead(MethodVisitor methodVisitor) {
1296 delegate.applyHead(methodVisitor);
1297 }
1298
1299 /**
1300 * {@inheritDoc}
1301 */
1302 public void applyBody(MethodVisitor methodVisitor,
1303 Implementation.Context implementationContext,
1304 AnnotationValueFilter.Factory annotationValueFilterFactory) {
1305 delegate.applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1306 }
1307
1308 /**
1309 * {@inheritDoc}
1310 */
1311 public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1312 delegate.applyAttributes(methodVisitor, annotationValueFilterFactory);
1313 }
1314
1315 /**
1316 * {@inheritDoc}
1317 */
1318 public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1319 return delegate.applyCode(methodVisitor, implementationContext);
1320 }
1321
1322 /**
1323 * A method representing an accessor bridge method.
1324 */
1325 protected static class AccessorBridge extends MethodDescription.InDefinedShape.AbstractBase {
1326
1327 /**
1328 * The target method of the bridge.
1329 */
1330 private final MethodDescription bridgeTarget;
1331
1332 /**
1333 * The bridge's type token.
1334 */
1335 private final MethodDescription.TypeToken bridgeType;
1336
1337 /**
1338 * The instrumented type defining the bridge target.
1339 */
1340 private final TypeDescription instrumentedType;
1341
1342 /**
1343 * Creates a new accessor bridge method.
1344 *
1345 * @param bridgeTarget The target method of the bridge.
1346 * @param bridgeType The bridge's type token.
1347 * @param instrumentedType The instrumented type defining the bridge target.
1348 */
1349 protected AccessorBridge(MethodDescription bridgeTarget, TypeToken bridgeType, TypeDescription instrumentedType) {
1350 this.bridgeTarget = bridgeTarget;
1351 this.bridgeType = bridgeType;
1352 this.instrumentedType = instrumentedType;
1353 }
1354
1355 /**
1356 * {@inheritDoc}
1357 */
1358 public TypeDescription getDeclaringType() {
1359 return instrumentedType;
1360 }
1361
1362 /**
1363 * {@inheritDoc}
1364 */
1365 public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1366 return new ParameterList.Explicit.ForTypes(this, bridgeType.getParameterTypes());
1367 }
1368
1369 /**
1370 * {@inheritDoc}
1371 */
1372 public TypeDescription.Generic getReturnType() {
1373 return bridgeType.getReturnType().asGenericType();
1374 }
1375
1376 /**
1377 * {@inheritDoc}
1378 */
1379 public TypeList.Generic getExceptionTypes() {
1380 return bridgeTarget.getExceptionTypes().accept(TypeDescription.Generic.Visitor.TypeErasing.INSTANCE);
1381 }
1382
1383 /**
1384 * {@inheritDoc}
1385 */
1386 public AnnotationValue<?, ?> getDefaultValue() {
1387 return AnnotationValue.UNDEFINED;
1388 }
1389
1390 /**
1391 * {@inheritDoc}
1392 */
1393 public TypeList.Generic getTypeVariables() {
1394 return new TypeList.Generic.Empty();
1395 }
1396
1397 /**
1398 * {@inheritDoc}
1399 */
1400 public AnnotationList getDeclaredAnnotations() {
1401 return new AnnotationList.Empty();
1402 }
1403
1404 /**
1405 * {@inheritDoc}
1406 */
1407 public int getModifiers() {
1408 return (bridgeTarget.getModifiers() | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC) & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE);
1409 }
1410
1411 /**
1412 * {@inheritDoc}
1413 */
1414 public String getInternalName() {
1415 return bridgeTarget.getInternalName();
1416 }
1417 }
1418
1419 /**
1420 * A method representing a bridge's target method in its defined shape.
1421 */
1422 protected static class BridgeTarget extends MethodDescription.InDefinedShape.AbstractBase {
1423
1424 /**
1425 * The target method of the bridge.
1426 */
1427 private final MethodDescription bridgeTarget;
1428
1429 /**
1430 * The instrumented type defining the bridge target.
1431 */
1432 private final TypeDescription instrumentedType;
1433
1434 /**
1435 * Creates a new bridge target.
1436 *
1437 * @param bridgeTarget The target method of the bridge.
1438 * @param instrumentedType The instrumented type defining the bridge target.
1439 */
1440 protected BridgeTarget(MethodDescription bridgeTarget, TypeDescription instrumentedType) {
1441 this.bridgeTarget = bridgeTarget;
1442 this.instrumentedType = instrumentedType;
1443 }
1444
1445 /**
1446 * {@inheritDoc}
1447 */
1448 public TypeDescription getDeclaringType() {
1449 return instrumentedType;
1450 }
1451
1452 /**
1453 * {@inheritDoc}
1454 */
1455 public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1456 return new ParameterList.ForTokens(this, bridgeTarget.getParameters().asTokenList(is(instrumentedType)));
1457 }
1458
1459 /**
1460 * {@inheritDoc}
1461 */
1462 public TypeDescription.Generic getReturnType() {
1463 return bridgeTarget.getReturnType();
1464 }
1465
1466 /**
1467 * {@inheritDoc}
1468 */
1469 public TypeList.Generic getExceptionTypes() {
1470 return bridgeTarget.getExceptionTypes();
1471 }
1472
1473 /**
1474 * {@inheritDoc}
1475 */
1476 public AnnotationValue<?, ?> getDefaultValue() {
1477 return bridgeTarget.getDefaultValue();
1478 }
1479
1480 /**
1481 * {@inheritDoc}
1482 */
1483 public TypeList.Generic getTypeVariables() {
1484 return bridgeTarget.getTypeVariables();
1485 }
1486
1487 /**
1488 * {@inheritDoc}
1489 */
1490 public AnnotationList getDeclaredAnnotations() {
1491 return bridgeTarget.getDeclaredAnnotations();
1492 }
1493
1494 /**
1495 * {@inheritDoc}
1496 */
1497 public int getModifiers() {
1498 return bridgeTarget.getModifiers();
1499 }
1500
1501 /**
1502 * {@inheritDoc}
1503 */
1504 public String getInternalName() {
1505 return bridgeTarget.getInternalName();
1506 }
1507 }
1508 }
1509 }
1510 }
1511
1512 /**
1513 * An record component pool that allows a lookup for how to implement a record component.
1514 */
1515 interface RecordComponentPool {
1516
1517 /**
1518 * Looks up a handler entry for a given record component.
1519 *
1520 * @param recordComponentDescription The record component being processed.
1521 * @return A handler entry for the given record component.
1522 */
1523 Record target(RecordComponentDescription recordComponentDescription);
1524
1525 /**
1526 * An entry of a record component pool that describes how a record component is implemented.
1527 *
1528 * @see RecordComponentPool
1529 */
1530 interface Record {
1531
1532 /**
1533 * Determines if this record is implicit, i.e is not defined by a {@link RecordComponentPool}.
1534 *
1535 * @return {@code true} if this record is implicit.
1536 */
1537 boolean isImplicit();
1538
1539 /**
1540 * Returns the record component that this record represents.
1541 *
1542 * @return The record component that this record represents.
1543 */
1544 RecordComponentDescription getRecordComponent();
1545
1546 /**
1547 * Returns the record component attribute appender for a given record component.
1548 *
1549 * @return The record component appender to be applied on the given field.
1550 */
1551 RecordComponentAttributeAppender getRecordComponentAppender();
1552
1553 /**
1554 * Writes this record to a given class visitor.
1555 *
1556 * @param classVisitor The class visitor to which this record is to be written to.
1557 * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
1558 */
1559 void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1560
1561 /**
1562 * Applies this record to a record component visitor. This is not possible for implicit records.
1563 *
1564 * @param recordComponentVisitor The record component visitor onto which this record is to be applied.
1565 * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
1566 */
1567 void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1568
1569 /**
1570 * A record for a simple field without a default value where all of the record component's declared annotations are appended.
1571 */
1572 @HashCodeAndEqualsPlugin.Enhance
1573 class ForImplicitRecordComponent implements Record {
1574
1575 /**
1576 * The implemented record component.
1577 */
1578 private final RecordComponentDescription recordComponentDescription;
1579
1580 /**
1581 * Creates a new record for a simple record component.
1582 *
1583 * @param recordComponentDescription The described record component.
1584 */
1585 public ForImplicitRecordComponent(RecordComponentDescription recordComponentDescription) {
1586 this.recordComponentDescription = recordComponentDescription;
1587 }
1588
1589 /**
1590 * {@inheritDoc}
1591 */
1592 public boolean isImplicit() {
1593 return true;
1594 }
1595
1596 /**
1597 * {@inheritDoc}
1598 */
1599 public RecordComponentDescription getRecordComponent() {
1600 return recordComponentDescription;
1601 }
1602
1603 /**
1604 * {@inheritDoc}
1605 */
1606 public RecordComponentAttributeAppender getRecordComponentAppender() {
1607 throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
1608 }
1609
1610 /**
1611 * {@inheritDoc}
1612 */
1613 public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1614 RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1615 recordComponentDescription.getDescriptor(),
1616 recordComponentDescription.getGenericSignature());
1617 if (recordComponentVisitor != null) {
1618 RecordComponentAttributeAppender.ForInstrumentedRecordComponent.INSTANCE.apply(recordComponentVisitor,
1619 recordComponentDescription,
1620 annotationValueFilterFactory.on(recordComponentDescription));
1621 recordComponentVisitor.visitEnd();
1622 }
1623 }
1624
1625 /**
1626 * {@inheritDoc}
1627 */
1628 public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1629 throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1630 }
1631 }
1632
1633 /**
1634 * A record for a rich record component with attributes.
1635 */
1636 @HashCodeAndEqualsPlugin.Enhance
1637 class ForExplicitRecordComponent implements Record {
1638
1639 /**
1640 * The attribute appender for the record component.
1641 */
1642 private final RecordComponentAttributeAppender attributeAppender;
1643
1644 /**
1645 * The implemented record component.
1646 */
1647 private final RecordComponentDescription recordComponentDescription;
1648
1649 /**
1650 * Creates a record for a rich record component.
1651 *
1652 * @param attributeAppender The attribute appender for the record component.
1653 * @param recordComponentDescription The implemented record component.
1654 */
1655 public ForExplicitRecordComponent(RecordComponentAttributeAppender attributeAppender, RecordComponentDescription recordComponentDescription) {
1656 this.attributeAppender = attributeAppender;
1657 this.recordComponentDescription = recordComponentDescription;
1658 }
1659
1660 /**
1661 * {@inheritDoc}
1662 */
1663 public boolean isImplicit() {
1664 return false;
1665 }
1666
1667 /**
1668 * {@inheritDoc}
1669 */
1670 public RecordComponentDescription getRecordComponent() {
1671 return recordComponentDescription;
1672 }
1673
1674 /**
1675 * {@inheritDoc}
1676 */
1677 public RecordComponentAttributeAppender getRecordComponentAppender() {
1678 return attributeAppender;
1679 }
1680
1681 /**
1682 * {@inheritDoc}
1683 */
1684 public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1685 RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1686 recordComponentDescription.getDescriptor(),
1687 recordComponentDescription.getGenericSignature());
1688 if (recordComponentVisitor != null) {
1689 attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1690 recordComponentVisitor.visitEnd();
1691 }
1692 }
1693
1694 /**
1695 * {@inheritDoc}
1696 */
1697 public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1698 attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1699 }
1700 }
1701 }
1702
1703 /**
1704 * A record component pool that does not allow any look ups.
1705 */
1706 enum Disabled implements RecordComponentPool {
1707
1708 /**
1709 * The singleton instance.
1710 */
1711 INSTANCE;
1712
1713 /**
1714 * {@inheritDoc}
1715 */
1716 public Record target(RecordComponentDescription recordComponentDescription) {
1717 throw new IllegalStateException("Cannot look up record component from disabled pool");
1718 }
1719 }
1720 }
1721
1722 /**
1723 * A default implementation of a {@link net.bytebuddy.dynamic.scaffold.TypeWriter}.
1724 *
1725 * @param <S> The best known loaded type for the dynamically created type.
1726 */
1727 @HashCodeAndEqualsPlugin.Enhance
1728 abstract class Default<S> implements TypeWriter<S> {
1729
1730 /**
1731 * Indicates an empty reference in a class file which is expressed by {@code null}.
1732 */
1733 private static final String NO_REFERENCE = null;
1734
1735 /**
1736 * A folder for dumping class files or {@code null} if no dump should be generated.
1737 */
1738 protected static final String DUMP_FOLDER;
1739
1740 /*
1741 * Reads the dumping property that is set at program start up. This might cause an error because of security constraints.
1742 */
1743 static {
1744 String dumpFolder;
1745 try {
1746 dumpFolder = AccessController.doPrivileged(new GetSystemPropertyAction(DUMP_PROPERTY));
1747 } catch (RuntimeException exception) {
1748 dumpFolder = null;
1749 }
1750 DUMP_FOLDER = dumpFolder;
1751 }
1752
1753 /**
1754 * The instrumented type to be created.
1755 */
1756 protected final TypeDescription instrumentedType;
1757
1758 /**
1759 * The class file specified by the user.
1760 */
1761 protected final ClassFileVersion classFileVersion;
1762
1763 /**
1764 * The field pool to use.
1765 */
1766 protected final FieldPool fieldPool;
1767
1768 /**
1769 * The record component pool to use.
1770 */
1771 protected final RecordComponentPool recordComponentPool;
1772
1773 /**
1774 * The explicit auxiliary types to add to the created type.
1775 */
1776 protected final List<? extends DynamicType> auxiliaryTypes;
1777
1778 /**
1779 * The instrumented type's declared fields.
1780 */
1781 protected final FieldList<FieldDescription.InDefinedShape> fields;
1782
1783 /**
1784 * The instrumented type's methods that are declared or inherited.
1785 */
1786 protected final MethodList<?> methods;
1787
1788 /**
1789 * The instrumented methods relevant to this type creation.
1790 */
1791 protected final MethodList<?> instrumentedMethods;
1792
1793 /**
1794 * The instrumented type's record components.
1795 */
1796 protected final RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents;
1797
1798 /**
1799 * The loaded type initializer to apply onto the created type after loading.
1800 */
1801 protected final LoadedTypeInitializer loadedTypeInitializer;
1802
1803 /**
1804 * The type initializer to include in the created type's type initializer.
1805 */
1806 protected final TypeInitializer typeInitializer;
1807
1808 /**
1809 * The type attribute appender to apply onto the instrumented type.
1810 */
1811 protected final TypeAttributeAppender typeAttributeAppender;
1812
1813 /**
1814 * The ASM visitor wrapper to apply onto the class writer.
1815 */
1816 protected final AsmVisitorWrapper asmVisitorWrapper;
1817
1818 /**
1819 * The annotation value filter factory to apply.
1820 */
1821 protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
1822
1823 /**
1824 * The annotation retention to apply.
1825 */
1826 protected final AnnotationRetention annotationRetention;
1827
1828 /**
1829 * The naming strategy for auxiliary types to apply.
1830 */
1831 protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1832
1833 /**
1834 * The implementation context factory to apply.
1835 */
1836 protected final Implementation.Context.Factory implementationContextFactory;
1837
1838 /**
1839 * Determines if a type should be explicitly validated.
1840 */
1841 protected final TypeValidation typeValidation;
1842
1843 /**
1844 * The class writer strategy to use.
1845 */
1846 protected final ClassWriterStrategy classWriterStrategy;
1847
1848 /**
1849 * The type pool to use for computing stack map frames, if required.
1850 */
1851 protected final TypePool typePool;
1852
1853 /**
1854 * Creates a new default type writer.
1855 *
1856 * @param instrumentedType The instrumented type to be created.
1857 * @param classFileVersion The class file specified by the user.
1858 * @param fieldPool The field pool to use.
1859 * @param recordComponentPool The record component pool to use.
1860 * @param auxiliaryTypes The explicit auxiliary types to add to the created type.
1861 * @param fields The instrumented type's declared fields.
1862 * @param methods The instrumented type's declared and virtually inherited methods.
1863 * @param instrumentedMethods The instrumented methods relevant to this type creation.
1864 * @param recordComponents The instrumented type's record components.
1865 * @param loadedTypeInitializer The loaded type initializer to apply onto the created type after loading.
1866 * @param typeInitializer The type initializer to include in the created type's type initializer.
1867 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
1868 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
1869 * @param annotationValueFilterFactory The annotation value filter factory to apply.
1870 * @param annotationRetention The annotation retention to apply.
1871 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
1872 * @param implementationContextFactory The implementation context factory to apply.
1873 * @param typeValidation Determines if a type should be explicitly validated.
1874 * @param classWriterStrategy The class writer strategy to use.
1875 * @param typePool The type pool to use for computing stack map frames, if required.
1876 */
1877 protected Default(TypeDescription instrumentedType,
1878 ClassFileVersion classFileVersion,
1879 FieldPool fieldPool,
1880 RecordComponentPool recordComponentPool,
1881 List<? extends DynamicType> auxiliaryTypes,
1882 FieldList<FieldDescription.InDefinedShape> fields,
1883 MethodList<?> methods,
1884 MethodList<?> instrumentedMethods,
1885 RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
1886 LoadedTypeInitializer loadedTypeInitializer,
1887 TypeInitializer typeInitializer,
1888 TypeAttributeAppender typeAttributeAppender,
1889 AsmVisitorWrapper asmVisitorWrapper,
1890 AnnotationValueFilter.Factory annotationValueFilterFactory,
1891 AnnotationRetention annotationRetention,
1892 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1893 Implementation.Context.Factory implementationContextFactory,
1894 TypeValidation typeValidation,
1895 ClassWriterStrategy classWriterStrategy,
1896 TypePool typePool) {
1897 this.instrumentedType = instrumentedType;
1898 this.classFileVersion = classFileVersion;
1899 this.fieldPool = fieldPool;
1900 this.recordComponentPool = recordComponentPool;
1901 this.auxiliaryTypes = auxiliaryTypes;
1902 this.fields = fields;
1903 this.methods = methods;
1904 this.instrumentedMethods = instrumentedMethods;
1905 this.recordComponents = recordComponents;
1906 this.loadedTypeInitializer = loadedTypeInitializer;
1907 this.typeInitializer = typeInitializer;
1908 this.typeAttributeAppender = typeAttributeAppender;
1909 this.asmVisitorWrapper = asmVisitorWrapper;
1910 this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1911 this.annotationValueFilterFactory = annotationValueFilterFactory;
1912 this.annotationRetention = annotationRetention;
1913 this.implementationContextFactory = implementationContextFactory;
1914 this.typeValidation = typeValidation;
1915 this.classWriterStrategy = classWriterStrategy;
1916 this.typePool = typePool;
1917 }
1918
1919 /**
1920 * Creates a type writer for creating a new type.
1921 *
1922 * @param methodRegistry The compiled method registry to use.
1923 * @param auxiliaryTypes A list of explicitly required auxiliary types.
1924 * @param fieldPool The field pool to use.
1925 * @param recordComponentPool The record component pool to use.
1926 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
1927 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
1928 * @param classFileVersion The class file version to use when no explicit class file version is applied.
1929 * @param annotationValueFilterFactory The annotation value filter factory to apply.
1930 * @param annotationRetention The annotation retention to apply.
1931 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
1932 * @param implementationContextFactory The implementation context factory to apply.
1933 * @param typeValidation Determines if a type should be explicitly validated.
1934 * @param classWriterStrategy The class writer strategy to use.
1935 * @param typePool The type pool to use for computing stack map frames, if required.
1936 * @param <U> A loaded type that the instrumented type guarantees to subclass.
1937 * @return A suitable type writer.
1938 */
1939 public static <U> TypeWriter<U> forCreation(MethodRegistry.Compiled methodRegistry,
1940 List<? extends DynamicType> auxiliaryTypes,
1941 FieldPool fieldPool,
1942 RecordComponentPool recordComponentPool,
1943 TypeAttributeAppender typeAttributeAppender,
1944 AsmVisitorWrapper asmVisitorWrapper,
1945 ClassFileVersion classFileVersion,
1946 AnnotationValueFilter.Factory annotationValueFilterFactory,
1947 AnnotationRetention annotationRetention,
1948 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1949 Implementation.Context.Factory implementationContextFactory,
1950 TypeValidation typeValidation,
1951 ClassWriterStrategy classWriterStrategy,
1952 TypePool typePool) {
1953 return new ForCreation<U>(methodRegistry.getInstrumentedType(),
1954 classFileVersion,
1955 fieldPool,
1956 methodRegistry,
1957 recordComponentPool,
1958 auxiliaryTypes,
1959 methodRegistry.getInstrumentedType().getDeclaredFields(),
1960 methodRegistry.getMethods(),
1961 methodRegistry.getInstrumentedMethods(),
1962 methodRegistry.getInstrumentedType().getRecordComponents(),
1963 methodRegistry.getLoadedTypeInitializer(),
1964 methodRegistry.getTypeInitializer(),
1965 typeAttributeAppender,
1966 asmVisitorWrapper,
1967 annotationValueFilterFactory,
1968 annotationRetention,
1969 auxiliaryTypeNamingStrategy,
1970 implementationContextFactory,
1971 typeValidation,
1972 classWriterStrategy,
1973 typePool);
1974 }
1975
1976 /**
1977 * Creates a type writer for redefining a type.
1978 *
1979 * @param methodRegistry The compiled method registry to use.
1980 * @param auxiliaryTypes A list of explicitly required auxiliary types.
1981 * @param fieldPool The field pool to use.
1982 * @param recordComponentPool The record component pool to use.
1983 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
1984 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
1985 * @param classFileVersion The class file version to use when no explicit class file version is applied.
1986 * @param annotationValueFilterFactory The annotation value filter factory to apply.
1987 * @param annotationRetention The annotation retention to apply.
1988 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
1989 * @param implementationContextFactory The implementation context factory to apply.
1990 * @param typeValidation Determines if a type should be explicitly validated.
1991 * @param classWriterStrategy The class writer strategy to use.
1992 * @param typePool The type pool to use for computing stack map frames, if required.
1993 * @param originalType The original type that is being redefined or rebased.
1994 * @param classFileLocator The class file locator for locating the original type's class file.
1995 * @param <U> A loaded type that the instrumented type guarantees to subclass.
1996 * @return A suitable type writer.
1997 */
1998 public static <U> TypeWriter<U> forRedefinition(MethodRegistry.Prepared methodRegistry,
1999 List<? extends DynamicType> auxiliaryTypes,
2000 FieldPool fieldPool,
2001 RecordComponentPool recordComponentPool,
2002 TypeAttributeAppender typeAttributeAppender,
2003 AsmVisitorWrapper asmVisitorWrapper,
2004 ClassFileVersion classFileVersion,
2005 AnnotationValueFilter.Factory annotationValueFilterFactory,
2006 AnnotationRetention annotationRetention,
2007 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2008 Implementation.Context.Factory implementationContextFactory,
2009 TypeValidation typeValidation,
2010 ClassWriterStrategy classWriterStrategy,
2011 TypePool typePool,
2012 TypeDescription originalType,
2013 ClassFileLocator classFileLocator) {
2014 return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
2015 classFileVersion,
2016 fieldPool,
2017 recordComponentPool,
2018 auxiliaryTypes,
2019 methodRegistry.getInstrumentedType().getDeclaredFields(),
2020 methodRegistry.getMethods(),
2021 methodRegistry.getInstrumentedMethods(),
2022 methodRegistry.getInstrumentedType().getRecordComponents(),
2023 methodRegistry.getLoadedTypeInitializer(),
2024 methodRegistry.getTypeInitializer(),
2025 typeAttributeAppender,
2026 asmVisitorWrapper,
2027 annotationValueFilterFactory,
2028 annotationRetention,
2029 auxiliaryTypeNamingStrategy,
2030 implementationContextFactory,
2031 typeValidation,
2032 classWriterStrategy,
2033 typePool,
2034 originalType,
2035 classFileLocator,
2036 methodRegistry,
2037 SubclassImplementationTarget.Factory.LEVEL_TYPE,
2038 MethodRebaseResolver.Disabled.INSTANCE);
2039 }
2040
2041 /**
2042 * Creates a type writer for rebasing a type.
2043 *
2044 * @param methodRegistry The compiled method registry to use.
2045 * @param auxiliaryTypes A list of explicitly required auxiliary types.
2046 * @param fieldPool The field pool to use.
2047 * @param recordComponentPool The record component pool to use.
2048 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
2049 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
2050 * @param classFileVersion The class file version to use when no explicit class file version is applied.
2051 * @param annotationValueFilterFactory The annotation value filter factory to apply.
2052 * @param annotationRetention The annotation retention to apply.
2053 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
2054 * @param implementationContextFactory The implementation context factory to apply.
2055 * @param typeValidation Determines if a type should be explicitly validated.
2056 * @param classWriterStrategy The class writer strategy to use.
2057 * @param typePool The type pool to use for computing stack map frames, if required.
2058 * @param originalType The original type that is being redefined or rebased.
2059 * @param classFileLocator The class file locator for locating the original type's class file.
2060 * @param methodRebaseResolver The method rebase resolver to use for rebasing names.
2061 * @param <U> A loaded type that the instrumented type guarantees to subclass.
2062 * @return A suitable type writer.
2063 */
2064 public static <U> TypeWriter<U> forRebasing(MethodRegistry.Prepared methodRegistry,
2065 List<? extends DynamicType> auxiliaryTypes,
2066 FieldPool fieldPool,
2067 RecordComponentPool recordComponentPool,
2068 TypeAttributeAppender typeAttributeAppender,
2069 AsmVisitorWrapper asmVisitorWrapper,
2070 ClassFileVersion classFileVersion,
2071 AnnotationValueFilter.Factory annotationValueFilterFactory,
2072 AnnotationRetention annotationRetention,
2073 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2074 Implementation.Context.Factory implementationContextFactory,
2075 TypeValidation typeValidation,
2076 ClassWriterStrategy classWriterStrategy,
2077 TypePool typePool,
2078 TypeDescription originalType,
2079 ClassFileLocator classFileLocator,
2080 MethodRebaseResolver methodRebaseResolver) {
2081 return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
2082 classFileVersion,
2083 fieldPool,
2084 recordComponentPool,
2085 CompoundList.of(auxiliaryTypes, methodRebaseResolver.getAuxiliaryTypes()),
2086 methodRegistry.getInstrumentedType().getDeclaredFields(),
2087 methodRegistry.getMethods(),
2088 methodRegistry.getInstrumentedMethods(),
2089 methodRegistry.getInstrumentedType().getRecordComponents(),
2090 methodRegistry.getLoadedTypeInitializer(),
2091 methodRegistry.getTypeInitializer(),
2092 typeAttributeAppender,
2093 asmVisitorWrapper,
2094 annotationValueFilterFactory,
2095 annotationRetention,
2096 auxiliaryTypeNamingStrategy,
2097 implementationContextFactory,
2098 typeValidation,
2099 classWriterStrategy,
2100 typePool,
2101 originalType,
2102 classFileLocator,
2103 methodRegistry,
2104 new RebaseImplementationTarget.Factory(methodRebaseResolver),
2105 methodRebaseResolver);
2106 }
2107
2108 /**
2109 * Creates a type writer for decorating a type.
2110 *
2111 * @param instrumentedType The instrumented type.
2112 * @param classFileVersion The class file version to use when no explicit class file version is applied.
2113 * @param auxiliaryTypes A list of explicitly required auxiliary types.
2114 * @param methods The methods to instrument.
2115 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
2116 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
2117 * @param annotationValueFilterFactory The annotation value filter factory to apply.
2118 * @param annotationRetention The annotation retention to apply.
2119 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
2120 * @param implementationContextFactory The implementation context factory to apply.
2121 * @param typeValidation Determines if a type should be explicitly validated.
2122 * @param classWriterStrategy The class writer strategy to use.
2123 * @param typePool The type pool to use for computing stack map frames, if required.
2124 * @param classFileLocator The class file locator for locating the original type's class file.
2125 * @param <U> A loaded type that the instrumented type guarantees to subclass.
2126 * @return A suitable type writer.
2127 */
2128 public static <U> TypeWriter<U> forDecoration(TypeDescription instrumentedType,
2129 ClassFileVersion classFileVersion,
2130 List<? extends DynamicType> auxiliaryTypes,
2131 List<? extends MethodDescription> methods,
2132 TypeAttributeAppender typeAttributeAppender,
2133 AsmVisitorWrapper asmVisitorWrapper,
2134 AnnotationValueFilter.Factory annotationValueFilterFactory,
2135 AnnotationRetention annotationRetention,
2136 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2137 Implementation.Context.Factory implementationContextFactory,
2138 TypeValidation typeValidation,
2139 ClassWriterStrategy classWriterStrategy,
2140 TypePool typePool,
2141 ClassFileLocator classFileLocator) {
2142 return new ForInlining.WithDecorationOnly<U>(instrumentedType,
2143 classFileVersion,
2144 auxiliaryTypes,
2145 new MethodList.Explicit<MethodDescription>(methods),
2146 typeAttributeAppender,
2147 asmVisitorWrapper,
2148 annotationValueFilterFactory,
2149 annotationRetention,
2150 auxiliaryTypeNamingStrategy,
2151 implementationContextFactory,
2152 typeValidation,
2153 classWriterStrategy,
2154 typePool,
2155 classFileLocator);
2156 }
2157
2158 /**
2159 * {@inheritDoc}
2160 */
2161 @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Setting a debugging property should never change the program outcome")
2162 public DynamicType.Unloaded<S> make(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2163 ClassDumpAction.Dispatcher dispatcher = DUMP_FOLDER == null
2164 ? ClassDumpAction.Dispatcher.Disabled.INSTANCE
2165 : new ClassDumpAction.Dispatcher.Enabled(DUMP_FOLDER, System.currentTimeMillis());
2166 UnresolvedType unresolvedType = create(typeResolutionStrategy.injectedInto(typeInitializer), dispatcher);
2167 dispatcher.dump(instrumentedType, false, unresolvedType.getBinaryRepresentation());
2168 return unresolvedType.toDynamicType(typeResolutionStrategy);
2169 }
2170
2171 /**
2172 * Creates an unresolved version of the dynamic type.
2173 *
2174 * @param typeInitializer The type initializer to use.
2175 * @param dispatcher A dispatcher for dumping class files.
2176 * @return An unresolved type.
2177 */
2178 protected abstract UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher);
2179
2180 /**
2181 * An unresolved type.
2182 */
2183 @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2184 protected class UnresolvedType {
2185
2186 /**
2187 * The type's binary representation.
2188 */
2189 private final byte[] binaryRepresentation;
2190
2191 /**
2192 * A list of auxiliary types for this unresolved type.
2193 */
2194 private final List<? extends DynamicType> auxiliaryTypes;
2195
2196 /**
2197 * Creates a new unresolved type.
2198 *
2199 * @param binaryRepresentation The type's binary representation.
2200 * @param auxiliaryTypes A list of auxiliary types for this unresolved type.
2201 */
2202 protected UnresolvedType(byte[] binaryRepresentation, List<? extends DynamicType> auxiliaryTypes) {
2203 this.binaryRepresentation = binaryRepresentation;
2204 this.auxiliaryTypes = auxiliaryTypes;
2205 }
2206
2207 /**
2208 * Resolves this type to a dynamic type.
2209 *
2210 * @param typeResolutionStrategy The type resolution strategy to apply.
2211 * @return A dynamic type representing the inlined type.
2212 */
2213 protected DynamicType.Unloaded<S> toDynamicType(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2214 return new DynamicType.Default.Unloaded<S>(instrumentedType,
2215 binaryRepresentation,
2216 loadedTypeInitializer,
2217 CompoundList.of(Default.this.auxiliaryTypes, auxiliaryTypes),
2218 typeResolutionStrategy);
2219 }
2220
2221 /**
2222 * Returns the binary representation of this unresolved type.
2223 *
2224 * @return The binary representation of this unresolved type.
2225 */
2226 protected byte[] getBinaryRepresentation() {
2227 return binaryRepresentation;
2228 }
2229 }
2230
2231 /**
2232 * A class validator that validates that a class only defines members that are appropriate for the sort of the generated class.
2233 */
2234 protected static class ValidatingClassVisitor extends ClassVisitor {
2235
2236 /**
2237 * Indicates that a method has no method parameters.
2238 */
2239 private static final String NO_PARAMETERS = "()";
2240
2241 /**
2242 * Indicates that a method returns void.
2243 */
2244 private static final String RETURNS_VOID = "V";
2245
2246 /**
2247 * The descriptor of the {@link String} type.
2248 */
2249 private static final String STRING_DESCRIPTOR = "Ljava/lang/String;";
2250
2251 /**
2252 * Indicates that a field is ignored.
2253 */
2254 private static final FieldVisitor IGNORE_FIELD = null;
2255
2256 /**
2257 * Indicates that a method is ignored.
2258 */
2259 private static final MethodVisitor IGNORE_METHOD = null;
2260
2261 /**
2262 * The constraint to assert the members against. The constraint is first defined when the general class information is visited.
2263 */
2264 private Constraint constraint;
2265
2266 /**
2267 * Creates a validating class visitor.
2268 *
2269 * @param classVisitor The class visitor to which any calls are delegated to.
2270 */
2271 protected ValidatingClassVisitor(ClassVisitor classVisitor) {
2272 super(OpenedClassReader.ASM_API, classVisitor);
2273 }
2274
2275 /**
2276 * Adds a validating visitor if type validation is enabled.
2277 *
2278 * @param classVisitor The original class visitor.
2279 * @param typeValidation The type validation state.
2280 * @return A class visitor that applies type validation if this is required.
2281 */
2282 protected static ClassVisitor of(ClassVisitor classVisitor, TypeValidation typeValidation) {
2283 return typeValidation.isEnabled()
2284 ? new ValidatingClassVisitor(classVisitor)
2285 : classVisitor;
2286 }
2287
2288 @Override
2289 public void visit(int version, int modifiers, String name, String signature, String superName, String[] interfaces) {
2290 ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(version);
2291 List<Constraint> constraints = new ArrayList<Constraint>();
2292 constraints.add(new Constraint.ForClassFileVersion(classFileVersion));
2293 if (name.endsWith('/' + PackageDescription.PACKAGE_CLASS_NAME)) {
2294 constraints.add(Constraint.ForPackageType.INSTANCE);
2295 } else if ((modifiers & Opcodes.ACC_ANNOTATION) != 0) {
2296 if (!classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
2297 throw new IllegalStateException("Cannot define an annotation type for class file version " + classFileVersion);
2298 }
2299 constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
2300 ? Constraint.ForAnnotation.JAVA_8
2301 : Constraint.ForAnnotation.CLASSIC);
2302 } else if ((modifiers & Opcodes.ACC_INTERFACE) != 0) {
2303 constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
2304 ? Constraint.ForInterface.JAVA_8
2305 : Constraint.ForInterface.CLASSIC);
2306 } else if ((modifiers & Opcodes.ACC_ABSTRACT) != 0) {
2307 constraints.add(Constraint.ForClass.ABSTRACT);
2308 } else {
2309 constraints.add(Constraint.ForClass.MANIFEST);
2310 }
2311 boolean record;
2312 if ((modifiers & Opcodes.ACC_RECORD) != 0) {
2313 constraints.add(Constraint.ForRecord.INSTANCE);
2314 record = true;
2315 } else {
2316 record = false;
2317 }
2318 constraint = new Constraint.Compound(constraints);
2319 constraint.assertType(modifiers, interfaces != null, signature != null);
2320 if (record) {
2321 constraint.assertRecord();
2322 }
2323 super.visit(version, modifiers, name, signature, superName, interfaces);
2324 }
2325
2326 @Override
2327 public void visitPermittedSubclass(String permittedSubclass) {
2328 constraint.assertPermittedSubclass();
2329 super.visitPermittedSubclass(permittedSubclass);
2330 }
2331
2332 @Override
2333 public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
2334 constraint.assertAnnotation();
2335 return super.visitAnnotation(descriptor, visible);
2336 }
2337
2338 @Override
2339 public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
2340 constraint.assertTypeAnnotation();
2341 return super.visitTypeAnnotation(typeReference, typePath, descriptor, visible);
2342 }
2343
2344 @Override
2345 public void visitNestHost(String nestHost) {
2346 constraint.assertNestMate();
2347 super.visitNestHost(nestHost);
2348 }
2349
2350 @Override
2351 public void visitNestMember(String nestMember) {
2352 constraint.assertNestMate();
2353 super.visitNestMember(nestMember);
2354 }
2355
2356 @Override
2357 public FieldVisitor visitField(int modifiers, String name, String descriptor, String signature, Object defaultValue) {
2358 if (defaultValue != null) {
2359 Class<?> type;
2360 switch (descriptor.charAt(0)) {
2361 case 'Z':
2362 case 'B':
2363 case 'C':
2364 case 'S':
2365 case 'I':
2366 type = Integer.class;
2367 break;
2368 case 'J':
2369 type = Long.class;
2370 break;
2371 case 'F':
2372 type = Float.class;
2373 break;
2374 case 'D':
2375 type = Double.class;
2376 break;
2377 default:
2378 if (!descriptor.equals(STRING_DESCRIPTOR)) {
2379 throw new IllegalStateException("Cannot define a default value for type of field " + name);
2380 }
2381 type = String.class;
2382 }
2383 if (!type.isInstance(defaultValue)) {
2384 throw new IllegalStateException("Field " + name + " defines an incompatible default value " + defaultValue);
2385 } else if (type == Integer.class) {
2386 int minimum, maximum;
2387 switch (descriptor.charAt(0)) {
2388 case 'Z':
2389 minimum = 0;
2390 maximum = 1;
2391 break;
2392 case 'B':
2393 minimum = Byte.MIN_VALUE;
2394 maximum = Byte.MAX_VALUE;
2395 break;
2396 case 'C':
2397 minimum = Character.MIN_VALUE;
2398 maximum = Character.MAX_VALUE;
2399 break;
2400 case 'S':
2401 minimum = Short.MIN_VALUE;
2402 maximum = Short.MAX_VALUE;
2403 break;
2404 default:
2405 minimum = Integer.MIN_VALUE;
2406 maximum = Integer.MAX_VALUE;
2407 }
2408 int value = (Integer) defaultValue;
2409 if (value < minimum || value > maximum) {
2410 throw new IllegalStateException("Field " + name + " defines an incompatible default value " + defaultValue);
2411 }
2412 }
2413 }
2414 constraint.assertField(name,
2415 (modifiers & Opcodes.ACC_PUBLIC) != 0,
2416 (modifiers & Opcodes.ACC_STATIC) != 0,
2417 (modifiers & Opcodes.ACC_FINAL) != 0,
2418 signature != null);
2419 FieldVisitor fieldVisitor = super.visitField(modifiers, name, descriptor, signature, defaultValue);
2420 return fieldVisitor == null
2421 ? IGNORE_FIELD
2422 : new ValidatingFieldVisitor(fieldVisitor);
2423 }
2424
2425 @Override
2426 public MethodVisitor visitMethod(int modifiers, String name, String descriptor, String signature, String[] exceptions) {
2427 constraint.assertMethod(name,
2428 (modifiers & Opcodes.ACC_ABSTRACT) != 0,
2429 (modifiers & Opcodes.ACC_PUBLIC) != 0,
2430 (modifiers & Opcodes.ACC_PRIVATE) != 0,
2431 (modifiers & Opcodes.ACC_STATIC) != 0,
2432 !name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)
2433 && !name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)
2434 && (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) == 0,
2435 name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME),
2436 !descriptor.startsWith(NO_PARAMETERS) || descriptor.endsWith(RETURNS_VOID),
2437 signature != null);
2438 MethodVisitor methodVisitor = super.visitMethod(modifiers, name, descriptor, signature, exceptions);
2439 return methodVisitor == null
2440 ? IGNORE_METHOD
2441 : new ValidatingMethodVisitor(methodVisitor, name);
2442 }
2443
2444 /**
2445 * A constraint for members that are legal for a given type.
2446 */
2447 protected interface Constraint {
2448
2449 /**
2450 * Asserts if the type can legally represent a package description.
2451 *
2452 * @param modifier The modifier that is to be written to the type.
2453 * @param definesInterfaces {@code true} if this type implements at least one interface.
2454 * @param isGeneric {@code true} if this type defines a generic type signature.
2455 */
2456 void assertType(int modifier, boolean definesInterfaces, boolean isGeneric);
2457
2458 /**
2459 * Asserts a field for being valid.
2460 *
2461 * @param name The name of the field.
2462 * @param isPublic {@code true} if this field is public.
2463 * @param isStatic {@code true} if this field is static.
2464 * @param isFinal {@code true} if this field is final.
2465 * @param isGeneric {@code true} if this field defines a generic signature.
2466 */
2467 void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric);
2468
2469 /**
2470 * Asserts a method for being valid.
2471 *
2472 * @param name The name of the method.
2473 * @param isAbstract {@code true} if the method is abstract.
2474 * @param isPublic {@code true} if this method is public.
2475 * @param isPrivate {@code true} if this method is private.
2476 * @param isStatic {@code true} if this method is static.
2477 * @param isVirtual {@code true} if this method is virtual.
2478 * @param isConstructor {@code true} if this method is a constructor.
2479 * @param isDefaultValueIncompatible {@code true} if a method's signature cannot describe an annotation property method.
2480 * @param isGeneric {@code true} if this method defines a generic signature.
2481 */
2482 void assertMethod(String name,
2483 boolean isAbstract,
2484 boolean isPublic,
2485 boolean isPrivate,
2486 boolean isStatic,
2487 boolean isVirtual,
2488 boolean isConstructor,
2489 boolean isDefaultValueIncompatible,
2490 boolean isGeneric);
2491
2492 /**
2493 * Asserts the legitimacy of an annotation for the instrumented type.
2494 */
2495 void assertAnnotation();
2496
2497 /**
2498 * Asserts the legitimacy of a type annotation for the instrumented type.
2499 */
2500 void assertTypeAnnotation();
2501
2502 /**
2503 * Asserts if a default value is legal for a method.
2504 *
2505 * @param name The name of the method.
2506 */
2507 void assertDefaultValue(String name);
2508
2509 /**
2510 * Asserts if it is legal to invoke a default method from a type.
2511 */
2512 void assertDefaultMethodCall();
2513
2514 /**
2515 * Asserts the capability to store a type constant in the class's constant pool.
2516 */
2517 void assertTypeInConstantPool();
2518
2519 /**
2520 * Asserts the capability to store a method type constant in the class's constant pool.
2521 */
2522 void assertMethodTypeInConstantPool();
2523
2524 /**
2525 * Asserts the capability to store a method handle in the class's constant pool.
2526 */
2527 void assertHandleInConstantPool();
2528
2529 /**
2530 * Asserts the capability to invoke a method dynamically.
2531 */
2532 void assertInvokeDynamic();
2533
2534 /**
2535 * Asserts the capability of executing a subroutine.
2536 */
2537 void assertSubRoutine();
2538
2539 /**
2540 * Asserts the capability of storing a dynamic value in the constant pool.
2541 */
2542 void assertDynamicValueInConstantPool();
2543
2544 /**
2545 * Asserts the capability of storing nest mate information.
2546 */
2547 void assertNestMate();
2548
2549 /**
2550 * Asserts the presence of a record component.
2551 */
2552 void assertRecord();
2553
2554 /**
2555 * Asserts the presence of a permitted subclass.
2556 */
2557 void assertPermittedSubclass();
2558
2559 /**
2560 * Represents the constraint of a class type.
2561 */
2562 enum ForClass implements Constraint {
2563
2564 /**
2565 * Represents the constraints of a non-abstract class.
2566 */
2567 MANIFEST(true),
2568
2569 /**
2570 * Represents the constraints of an abstract class.
2571 */
2572 ABSTRACT(false);
2573
2574 /**
2575 * {@code true} if this instance represents the constraints a non-abstract class.
2576 */
2577 private final boolean manifestType;
2578
2579 /**
2580 * Creates a new constraint for a class.
2581 *
2582 * @param manifestType {@code true} if this instance represents a non-abstract class.
2583 */
2584 ForClass(boolean manifestType) {
2585 this.manifestType = manifestType;
2586 }
2587
2588 /**
2589 * {@inheritDoc}
2590 */
2591 public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2592 /* do nothing */
2593 }
2594
2595 /**
2596 * {@inheritDoc}
2597 */
2598 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2599 /* do nothing */
2600 }
2601
2602 /**
2603 * {@inheritDoc}
2604 */
2605 public void assertMethod(String name,
2606 boolean isAbstract,
2607 boolean isPublic,
2608 boolean isPrivate,
2609 boolean isStatic,
2610 boolean isVirtual,
2611 boolean isConstructor,
2612 boolean isDefaultValueIncompatible,
2613 boolean isGeneric) {
2614 if (isAbstract && manifestType) {
2615 throw new IllegalStateException("Cannot define abstract method '" + name + "' for non-abstract class");
2616 }
2617 }
2618
2619 /**
2620 * {@inheritDoc}
2621 */
2622 public void assertAnnotation() {
2623 /* do nothing */
2624 }
2625
2626 /**
2627 * {@inheritDoc}
2628 */
2629 public void assertTypeAnnotation() {
2630 /* do nothing */
2631 }
2632
2633 /**
2634 * {@inheritDoc}
2635 */
2636 public void assertDefaultValue(String name) {
2637 throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
2638 }
2639
2640 /**
2641 * {@inheritDoc}
2642 */
2643 public void assertDefaultMethodCall() {
2644 /* do nothing */
2645 }
2646
2647 /**
2648 * {@inheritDoc}
2649 */
2650 public void assertTypeInConstantPool() {
2651 /* do nothing */
2652 }
2653
2654 /**
2655 * {@inheritDoc}
2656 */
2657 public void assertMethodTypeInConstantPool() {
2658 /* do nothing */
2659 }
2660
2661 /**
2662 * {@inheritDoc}
2663 */
2664 public void assertHandleInConstantPool() {
2665 /* do nothing */
2666 }
2667
2668 /**
2669 * {@inheritDoc}
2670 */
2671 public void assertInvokeDynamic() {
2672 /* do nothing */
2673 }
2674
2675 /**
2676 * {@inheritDoc}
2677 */
2678 public void assertSubRoutine() {
2679 /* do nothing */
2680 }
2681
2682 /**
2683 * {@inheritDoc}
2684 */
2685 public void assertDynamicValueInConstantPool() {
2686 /* do nothing */
2687 }
2688
2689 /**
2690 * {@inheritDoc}
2691 */
2692 public void assertNestMate() {
2693 /* do nothing */
2694 }
2695
2696 /**
2697 * {@inheritDoc}
2698 */
2699 public void assertRecord() {
2700 /* do nothing */
2701 }
2702
2703 /**
2704 * {@inheritDoc}
2705 */
2706 public void assertPermittedSubclass() {
2707 /* do nothing */
2708 }
2709 }
2710
2711 /**
2712 * Represents the constraint of a package type.
2713 */
2714 enum ForPackageType implements Constraint {
2715
2716 /**
2717 * The singleton instance.
2718 */
2719 INSTANCE;
2720
2721 /**
2722 * {@inheritDoc}
2723 */
2724 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2725 throw new IllegalStateException("Cannot define a field for a package description type");
2726 }
2727
2728 /**
2729 * {@inheritDoc}
2730 */
2731 public void assertMethod(String name,
2732 boolean isAbstract,
2733 boolean isPublic,
2734 boolean isPrivate,
2735 boolean isStatic,
2736 boolean isVirtual,
2737 boolean isConstructor,
2738 boolean isNoDefaultValue,
2739 boolean isGeneric) {
2740 throw new IllegalStateException("Cannot define a method for a package description type");
2741 }
2742
2743 /**
2744 * {@inheritDoc}
2745 */
2746 public void assertAnnotation() {
2747 /* do nothing */
2748 }
2749
2750 /**
2751 * {@inheritDoc}
2752 */
2753 public void assertTypeAnnotation() {
2754 /* do nothing */
2755 }
2756
2757 /**
2758 * {@inheritDoc}
2759 */
2760 public void assertDefaultValue(String name) {
2761 /* do nothing, implicit by forbidding methods */
2762 }
2763
2764 /**
2765 * {@inheritDoc}
2766 */
2767 public void assertDefaultMethodCall() {
2768 /* do nothing */
2769 }
2770
2771 /**
2772 * {@inheritDoc}
2773 */
2774 public void assertTypeInConstantPool() {
2775 /* do nothing */
2776 }
2777
2778 /**
2779 * {@inheritDoc}
2780 */
2781 public void assertMethodTypeInConstantPool() {
2782 /* do nothing */
2783 }
2784
2785 /**
2786 * {@inheritDoc}
2787 */
2788 public void assertHandleInConstantPool() {
2789 /* do nothing */
2790 }
2791
2792 /**
2793 * {@inheritDoc}
2794 */
2795 public void assertInvokeDynamic() {
2796 /* do nothing */
2797 }
2798
2799 /**
2800 * {@inheritDoc}
2801 */
2802 public void assertSubRoutine() {
2803 /* do nothing */
2804 }
2805
2806 /**
2807 * {@inheritDoc}
2808 */
2809 public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2810 if (modifier != PackageDescription.PACKAGE_MODIFIERS) {
2811 throw new IllegalStateException("A package description type must define " + PackageDescription.PACKAGE_MODIFIERS + " as modifier");
2812 } else if (definesInterfaces) {
2813 throw new IllegalStateException("Cannot implement interface for package type");
2814 }
2815 }
2816
2817 /**
2818 * {@inheritDoc}
2819 */
2820 public void assertDynamicValueInConstantPool() {
2821 /* do nothing */
2822 }
2823
2824 /**
2825 * {@inheritDoc}
2826 */
2827 public void assertNestMate() {
2828 /* do nothing */
2829 }
2830
2831 /**
2832 * {@inheritDoc}
2833 */
2834 public void assertRecord() {
2835 /* do nothing */
2836 }
2837
2838 /**
2839 * {@inheritDoc}
2840 */
2841 public void assertPermittedSubclass() {
2842 /* do nothing */
2843 }
2844 }
2845
2846 /**
2847 * Represents the constraint of an interface type.
2848 */
2849 enum ForInterface implements Constraint {
2850
2851 /**
2852 * An interface type with the constrains for the Java versions 5 to 7.
2853 */
2854 CLASSIC(true),
2855
2856 /**
2857 * An interface type with the constrains for the Java versions 8+.
2858 */
2859 JAVA_8(false);
2860
2861 /**
2862 * {@code true} if this instance represents a classic interface type (pre Java 8).
2863 */
2864 private final boolean classic;
2865
2866 /**
2867 * Creates a constraint for an interface type.
2868 *
2869 * @param classic {@code true} if this instance represents a classic interface (pre Java 8).
2870 */
2871 ForInterface(boolean classic) {
2872 this.classic = classic;
2873 }
2874
2875 /**
2876 * {@inheritDoc}
2877 */
2878 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2879 if (!isStatic || !isPublic || !isFinal) {
2880 throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
2881 }
2882 }
2883
2884 /**
2885 * {@inheritDoc}
2886 */
2887 public void assertMethod(String name,
2888 boolean isAbstract,
2889 boolean isPublic,
2890 boolean isPrivate,
2891 boolean isStatic,
2892 boolean isVirtual,
2893 boolean isConstructor,
2894 boolean isDefaultValueIncompatible,
2895 boolean isGeneric) {
2896 if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
2897 if (isConstructor) {
2898 throw new IllegalStateException("Cannot define constructor for interface type");
2899 } else if (classic && !isPublic) {
2900 throw new IllegalStateException("Cannot define non-public method '" + name + "' for interface type");
2901 } else if (classic && !isVirtual) {
2902 throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 interface type");
2903 } else if (classic && !isAbstract) {
2904 throw new IllegalStateException("Cannot define default method '" + name + "' for pre-Java 8 interface type");
2905 }
2906 }
2907 }
2908
2909 /**
2910 * {@inheritDoc}
2911 */
2912 public void assertAnnotation() {
2913 /* do nothing */
2914 }
2915
2916 /**
2917 * {@inheritDoc}
2918 */
2919 public void assertTypeAnnotation() {
2920 /* do nothing */
2921 }
2922
2923 /**
2924 * {@inheritDoc}
2925 */
2926 public void assertDefaultValue(String name) {
2927 throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
2928 }
2929
2930 /**
2931 * {@inheritDoc}
2932 */
2933 public void assertDefaultMethodCall() {
2934 /* do nothing */
2935 }
2936
2937 /**
2938 * {@inheritDoc}
2939 */
2940 public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2941 /* do nothing */
2942 }
2943
2944 /**
2945 * {@inheritDoc}
2946 */
2947 public void assertTypeInConstantPool() {
2948 /* do nothing */
2949 }
2950
2951 /**
2952 * {@inheritDoc}
2953 */
2954 public void assertMethodTypeInConstantPool() {
2955 /* do nothing */
2956 }
2957
2958 /**
2959 * {@inheritDoc}
2960 */
2961 public void assertHandleInConstantPool() {
2962 /* do nothing */
2963 }
2964
2965 /**
2966 * {@inheritDoc}
2967 */
2968 public void assertInvokeDynamic() {
2969 /* do nothing */
2970 }
2971
2972 /**
2973 * {@inheritDoc}
2974 */
2975 public void assertSubRoutine() {
2976 /* do nothing */
2977 }
2978
2979 /**
2980 * {@inheritDoc}
2981 */
2982 public void assertDynamicValueInConstantPool() {
2983 /* do nothing */
2984 }
2985
2986 /**
2987 * {@inheritDoc}
2988 */
2989 public void assertNestMate() {
2990 /* do nothing */
2991 }
2992
2993 /**
2994 * {@inheritDoc}
2995 */
2996 public void assertRecord() {
2997 /* do nothing */
2998 }
2999
3000 /**
3001 * {@inheritDoc}
3002 */
3003 public void assertPermittedSubclass() {
3004 /* do nothing */
3005 }
3006 }
3007
3008 /**
3009 * Represents the constraint of a record type.
3010 */
3011 enum ForRecord implements Constraint {
3012
3013 /**
3014 * The singleton instance.
3015 */
3016 INSTANCE;
3017
3018 /**
3019 * {@inheritDoc}
3020 */
3021 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3022 /* do nothing */
3023 }
3024
3025 /**
3026 * {@inheritDoc}
3027 */
3028 public void assertMethod(String name,
3029 boolean isAbstract,
3030 boolean isPublic,
3031 boolean isPrivate,
3032 boolean isStatic,
3033 boolean isVirtual,
3034 boolean isConstructor,
3035 boolean isDefaultValueIncompatible,
3036 boolean isGeneric) {
3037 /* do nothing */
3038 }
3039
3040 /**
3041 * {@inheritDoc}
3042 */
3043 public void assertAnnotation() {
3044 /* do nothing */
3045 }
3046
3047 /**
3048 * {@inheritDoc}
3049 */
3050 public void assertTypeAnnotation() {
3051 /* do nothing */
3052 }
3053
3054 /**
3055 * {@inheritDoc}
3056 */
3057 public void assertDefaultValue(String name) {
3058 /* do nothing */
3059 }
3060
3061 /**
3062 * {@inheritDoc}
3063 */
3064 public void assertDefaultMethodCall() {
3065 /* do nothing */
3066 }
3067
3068 /**
3069 * {@inheritDoc}
3070 */
3071 public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3072 if ((modifier & Opcodes.ACC_ABSTRACT) != 0) {
3073 throw new IllegalStateException("Cannot define a record class as abstract");
3074 }
3075 }
3076
3077 /**
3078 * {@inheritDoc}
3079 */
3080 public void assertTypeInConstantPool() {
3081 /* do nothing */
3082 }
3083
3084 /**
3085 * {@inheritDoc}
3086 */
3087 public void assertMethodTypeInConstantPool() {
3088 /* do nothing */
3089 }
3090
3091 /**
3092 * {@inheritDoc}
3093 */
3094 public void assertHandleInConstantPool() {
3095 /* do nothing */
3096 }
3097
3098 /**
3099 * {@inheritDoc}
3100 */
3101 public void assertInvokeDynamic() {
3102 /* do nothing */
3103 }
3104
3105 /**
3106 * {@inheritDoc}
3107 */
3108 public void assertSubRoutine() {
3109 /* do nothing */
3110 }
3111
3112 /**
3113 * {@inheritDoc}
3114 */
3115 public void assertDynamicValueInConstantPool() {
3116 /* do nothing */
3117 }
3118
3119 /**
3120 * {@inheritDoc}
3121 */
3122 public void assertNestMate() {
3123 /* do nothing */
3124 }
3125
3126 /**
3127 * {@inheritDoc}
3128 */
3129 public void assertRecord() {
3130 /* do nothing */
3131 }
3132
3133 /**
3134 * {@inheritDoc}
3135 */
3136 public void assertPermittedSubclass() {
3137 /* do nothing */
3138 }
3139 }
3140
3141 /**
3142 * Represents the constraint of an annotation type.
3143 */
3144 enum ForAnnotation implements Constraint {
3145
3146 /**
3147 * An annotation type with the constrains for the Java versions 5 to 7.
3148 */
3149 CLASSIC(true),
3150
3151 /**
3152 * An annotation type with the constrains for the Java versions 8+.
3153 */
3154 JAVA_8(false);
3155
3156 /**
3157 * {@code true} if this instance represents a classic annotation type (pre Java 8).
3158 */
3159 private final boolean classic;
3160
3161 /**
3162 * Creates a constraint for an annotation type.
3163 *
3164 * @param classic {@code true} if this instance represents a classic annotation type (pre Java 8).
3165 */
3166 ForAnnotation(boolean classic) {
3167 this.classic = classic;
3168 }
3169
3170 /**
3171 * {@inheritDoc}
3172 */
3173 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3174 if (!isStatic || !isPublic || !isFinal) {
3175 throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
3176 }
3177 }
3178
3179 /**
3180 * {@inheritDoc}
3181 */
3182 public void assertMethod(String name,
3183 boolean isAbstract,
3184 boolean isPublic,
3185 boolean isPrivate,
3186 boolean isStatic,
3187 boolean isVirtual,
3188 boolean isConstructor,
3189 boolean isDefaultValueIncompatible,
3190 boolean isGeneric) {
3191 if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
3192 if (isConstructor) {
3193 throw new IllegalStateException("Cannot define constructor for interface type");
3194 } else if (classic && !isVirtual) {
3195 throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 annotation type");
3196 } else if (!isStatic && isDefaultValueIncompatible) {
3197 throw new IllegalStateException("Cannot define method '" + name + "' with the given signature as an annotation type method");
3198 }
3199 }
3200 }
3201
3202 /**
3203 * {@inheritDoc}
3204 */
3205 public void assertAnnotation() {
3206 /* do nothing */
3207 }
3208
3209 /**
3210 * {@inheritDoc}
3211 */
3212 public void assertTypeAnnotation() {
3213 /* do nothing */
3214 }
3215
3216 /**
3217 * {@inheritDoc}
3218 */
3219 public void assertDefaultValue(String name) {
3220 /* do nothing */
3221 }
3222
3223 /**
3224 * {@inheritDoc}
3225 */
3226 public void assertDefaultMethodCall() {
3227 /* do nothing */
3228 }
3229
3230 /**
3231 * {@inheritDoc}
3232 */
3233 public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3234 if ((modifier & Opcodes.ACC_INTERFACE) == 0) {
3235 throw new IllegalStateException("Cannot define annotation type without interface modifier");
3236 }
3237 }
3238
3239 /**
3240 * {@inheritDoc}
3241 */
3242 public void assertTypeInConstantPool() {
3243 /* do nothing */
3244 }
3245
3246 /**
3247 * {@inheritDoc}
3248 */
3249 public void assertMethodTypeInConstantPool() {
3250 /* do nothing */
3251 }
3252
3253 /**
3254 * {@inheritDoc}
3255 */
3256 public void assertHandleInConstantPool() {
3257 /* do nothing */
3258 }
3259
3260 /**
3261 * {@inheritDoc}
3262 */
3263 public void assertInvokeDynamic() {
3264 /* do nothing */
3265 }
3266
3267 /**
3268 * {@inheritDoc}
3269 */
3270 public void assertSubRoutine() {
3271 /* do nothing */
3272 }
3273
3274 /**
3275 * {@inheritDoc}
3276 */
3277 public void assertDynamicValueInConstantPool() {
3278 /* do nothing */
3279 }
3280
3281 /**
3282 * {@inheritDoc}
3283 */
3284 public void assertNestMate() {
3285 /* do nothing */
3286 }
3287
3288 /**
3289 * {@inheritDoc}
3290 */
3291 public void assertRecord() {
3292 /* do nothing */
3293 }
3294
3295 /**
3296 * {@inheritDoc}
3297 */
3298 public void assertPermittedSubclass() {
3299 /* do nothing */
3300 }
3301 }
3302
3303 /**
3304 * Represents the constraint implied by a class file version.
3305 */
3306 @HashCodeAndEqualsPlugin.Enhance
3307 class ForClassFileVersion implements Constraint {
3308
3309 /**
3310 * The enforced class file version.
3311 */
3312 private final ClassFileVersion classFileVersion;
3313
3314 /**
3315 * Creates a new constraint for the given class file version.
3316 *
3317 * @param classFileVersion The enforced class file version.
3318 */
3319 protected ForClassFileVersion(ClassFileVersion classFileVersion) {
3320 this.classFileVersion = classFileVersion;
3321 }
3322
3323 /**
3324 * {@inheritDoc}
3325 */
3326 public void assertType(int modifiers, boolean definesInterfaces, boolean isGeneric) {
3327 if ((modifiers & Opcodes.ACC_ANNOTATION) != 0 && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
3328 throw new IllegalStateException("Cannot define annotation type for class file version " + classFileVersion);
3329 } else if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
3330 throw new IllegalStateException("Cannot define a generic type for class file version " + classFileVersion);
3331 }
3332 }
3333
3334 /**
3335 * {@inheritDoc}
3336 */
3337 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3338 if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
3339 throw new IllegalStateException("Cannot define generic field '" + name + "' for class file version " + classFileVersion);
3340 }
3341 }
3342
3343 /**
3344 * {@inheritDoc}
3345 */
3346 public void assertMethod(String name,
3347 boolean isAbstract,
3348 boolean isPublic,
3349 boolean isPrivate,
3350 boolean isStatic,
3351 boolean isVirtual,
3352 boolean isConstructor,
3353 boolean isDefaultValueIncompatible,
3354 boolean isGeneric) {
3355 if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
3356 throw new IllegalStateException("Cannot define generic method '" + name + "' for class file version " + classFileVersion);
3357 } else if (!isVirtual && isAbstract) {
3358 throw new IllegalStateException("Cannot define static or non-virtual method '" + name + "' to be abstract");
3359 }
3360 }
3361
3362 /**
3363 * {@inheritDoc}
3364 */
3365 public void assertAnnotation() {
3366 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
3367 throw new IllegalStateException("Cannot write annotations for class file version " + classFileVersion);
3368 }
3369 }
3370
3371 /**
3372 * {@inheritDoc}
3373 */
3374 public void assertTypeAnnotation() {
3375 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
3376 throw new IllegalStateException("Cannot write type annotations for class file version " + classFileVersion);
3377 }
3378 }
3379
3380 /**
3381 * {@inheritDoc}
3382 */
3383 public void assertDefaultValue(String name) {
3384 /* do nothing, implicitly checked by type assertion */
3385 }
3386
3387 /**
3388 * {@inheritDoc}
3389 */
3390 public void assertDefaultMethodCall() {
3391 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V8)) {
3392 throw new IllegalStateException("Cannot invoke default method for class file version " + classFileVersion);
3393 }
3394 }
3395
3396 /**
3397 * {@inheritDoc}
3398 */
3399 public void assertTypeInConstantPool() {
3400 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
3401 throw new IllegalStateException("Cannot write type to constant pool for class file version " + classFileVersion);
3402 }
3403 }
3404
3405 /**
3406 * {@inheritDoc}
3407 */
3408 public void assertMethodTypeInConstantPool() {
3409 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
3410 throw new IllegalStateException("Cannot write method type to constant pool for class file version " + classFileVersion);
3411 }
3412 }
3413
3414 /**
3415 * {@inheritDoc}
3416 */
3417 public void assertHandleInConstantPool() {
3418 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
3419 throw new IllegalStateException("Cannot write method handle to constant pool for class file version " + classFileVersion);
3420 }
3421 }
3422
3423 /**
3424 * {@inheritDoc}
3425 */
3426 public void assertInvokeDynamic() {
3427 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
3428 throw new IllegalStateException("Cannot write invoke dynamic instruction for class file version " + classFileVersion);
3429 }
3430 }
3431
3432 /**
3433 * {@inheritDoc}
3434 */
3435 public void assertSubRoutine() {
3436 if (classFileVersion.isGreaterThan(ClassFileVersion.JAVA_V5)) {
3437 throw new IllegalStateException("Cannot write subroutine for class file version " + classFileVersion);
3438 }
3439 }
3440
3441 /**
3442 * {@inheritDoc}
3443 */
3444 public void assertDynamicValueInConstantPool() {
3445 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
3446 throw new IllegalStateException("Cannot write dynamic constant for class file version " + classFileVersion);
3447 }
3448 }
3449
3450 /**
3451 * {@inheritDoc}
3452 */
3453 public void assertNestMate() {
3454 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
3455 throw new IllegalStateException("Cannot define nest mate for class file version " + classFileVersion);
3456 }
3457 }
3458
3459 /**
3460 * {@inheritDoc}
3461 */
3462 public void assertRecord() {
3463 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V14)) {
3464 throw new IllegalStateException("Cannot define record for class file version " + classFileVersion);
3465 }
3466 }
3467
3468 /**
3469 * {@inheritDoc}
3470 */
3471 public void assertPermittedSubclass() {
3472 if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V15)) {
3473 throw new IllegalStateException("Cannot define permitted subclasses for class file version " + classFileVersion);
3474 }
3475 }
3476 }
3477
3478 /**
3479 * A constraint implementation that summarizes several constraints.
3480 */
3481 @HashCodeAndEqualsPlugin.Enhance
3482 class Compound implements Constraint {
3483
3484 /**
3485 * A list of constraints that is enforced in the given order.
3486 */
3487 private final List<Constraint> constraints;
3488
3489 /**
3490 * Creates a new compound constraint.
3491 *
3492 * @param constraints A list of constraints that is enforced in the given order.
3493 */
3494 public Compound(List<? extends Constraint> constraints) {
3495 this.constraints = new ArrayList<Constraint>();
3496 for (Constraint constraint : constraints) {
3497 if (constraint instanceof Compound) {
3498 this.constraints.addAll(((Compound) constraint).constraints);
3499 } else {
3500 this.constraints.add(constraint);
3501 }
3502 }
3503 }
3504
3505 /**
3506 * {@inheritDoc}
3507 */
3508 public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3509 for (Constraint constraint : constraints) {
3510 constraint.assertType(modifier, definesInterfaces, isGeneric);
3511 }
3512 }
3513
3514 /**
3515 * {@inheritDoc}
3516 */
3517 public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3518 for (Constraint constraint : constraints) {
3519 constraint.assertField(name, isPublic, isStatic, isFinal, isGeneric);
3520 }
3521 }
3522
3523 /**
3524 * {@inheritDoc}
3525 */
3526 public void assertMethod(String name,
3527 boolean isAbstract,
3528 boolean isPublic,
3529 boolean isPrivate,
3530 boolean isStatic,
3531 boolean isVirtual,
3532 boolean isConstructor,
3533 boolean isDefaultValueIncompatible,
3534 boolean isGeneric) {
3535 for (Constraint constraint : constraints) {
3536 constraint.assertMethod(name,
3537 isAbstract,
3538 isPublic,
3539 isPrivate,
3540 isStatic,
3541 isVirtual,
3542 isConstructor,
3543 isDefaultValueIncompatible,
3544 isGeneric);
3545 }
3546 }
3547
3548 /**
3549 * {@inheritDoc}
3550 */
3551 public void assertDefaultValue(String name) {
3552 for (Constraint constraint : constraints) {
3553 constraint.assertDefaultValue(name);
3554 }
3555 }
3556
3557 /**
3558 * {@inheritDoc}
3559 */
3560 public void assertDefaultMethodCall() {
3561 for (Constraint constraint : constraints) {
3562 constraint.assertDefaultMethodCall();
3563 }
3564 }
3565
3566 /**
3567 * {@inheritDoc}
3568 */
3569 public void assertAnnotation() {
3570 for (Constraint constraint : constraints) {
3571 constraint.assertAnnotation();
3572 }
3573 }
3574
3575 /**
3576 * {@inheritDoc}
3577 */
3578 public void assertTypeAnnotation() {
3579 for (Constraint constraint : constraints) {
3580 constraint.assertTypeAnnotation();
3581 }
3582 }
3583
3584 /**
3585 * {@inheritDoc}
3586 */
3587 public void assertTypeInConstantPool() {
3588 for (Constraint constraint : constraints) {
3589 constraint.assertTypeInConstantPool();
3590 }
3591 }
3592
3593 /**
3594 * {@inheritDoc}
3595 */
3596 public void assertMethodTypeInConstantPool() {
3597 for (Constraint constraint : constraints) {
3598 constraint.assertMethodTypeInConstantPool();
3599 }
3600 }
3601
3602 /**
3603 * {@inheritDoc}
3604 */
3605 public void assertHandleInConstantPool() {
3606 for (Constraint constraint : constraints) {
3607 constraint.assertHandleInConstantPool();
3608 }
3609 }
3610
3611 /**
3612 * {@inheritDoc}
3613 */
3614 public void assertInvokeDynamic() {
3615 for (Constraint constraint : constraints) {
3616 constraint.assertInvokeDynamic();
3617 }
3618 }
3619
3620 /**
3621 * {@inheritDoc}
3622 */
3623 public void assertSubRoutine() {
3624 for (Constraint constraint : constraints) {
3625 constraint.assertSubRoutine();
3626 }
3627 }
3628
3629 /**
3630 * {@inheritDoc}
3631 */
3632 public void assertDynamicValueInConstantPool() {
3633 for (Constraint constraint : constraints) {
3634 constraint.assertDynamicValueInConstantPool();
3635 }
3636 }
3637
3638 /**
3639 * {@inheritDoc}
3640 */
3641 public void assertNestMate() {
3642 for (Constraint constraint : constraints) {
3643 constraint.assertNestMate();
3644 }
3645 }
3646
3647 /**
3648 * {@inheritDoc}
3649 */
3650 public void assertRecord() {
3651 for (Constraint constraint : constraints) {
3652 constraint.assertRecord();
3653 }
3654 }
3655
3656 /**
3657 * {@inheritDoc}
3658 */
3659 public void assertPermittedSubclass() {
3660 for (Constraint constraint : constraints) {
3661 constraint.assertPermittedSubclass();
3662 }
3663 }
3664 }
3665 }
3666
3667 /**
3668 * A field validator for checking default values.
3669 */
3670 protected class ValidatingFieldVisitor extends FieldVisitor {
3671
3672 /**
3673 * Creates a validating field visitor.
3674 *
3675 * @param fieldVisitor The field visitor to which any calls are delegated to.
3676 */
3677 protected ValidatingFieldVisitor(FieldVisitor fieldVisitor) {
3678 super(OpenedClassReader.ASM_API, fieldVisitor);
3679 }
3680
3681 @Override
3682 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
3683 constraint.assertAnnotation();
3684 return super.visitAnnotation(desc, visible);
3685 }
3686 }
3687
3688 /**
3689 * A method validator for checking default values.
3690 */
3691 protected class ValidatingMethodVisitor extends MethodVisitor {
3692
3693 /**
3694 * The name of the method being visited.
3695 */
3696 private final String name;
3697
3698 /**
3699 * Creates a validating method visitor.
3700 *
3701 * @param methodVisitor The method visitor to which any calls are delegated to.
3702 * @param name The name of the method being visited.
3703 */
3704 protected ValidatingMethodVisitor(MethodVisitor methodVisitor, String name) {
3705 super(OpenedClassReader.ASM_API, methodVisitor);
3706 this.name = name;
3707 }
3708
3709 @Override
3710 public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
3711 constraint.assertAnnotation();
3712 return super.visitAnnotation(desc, visible);
3713 }
3714
3715 @Override
3716 public AnnotationVisitor visitAnnotationDefault() {
3717 constraint.assertDefaultValue(name);
3718 return super.visitAnnotationDefault();
3719 }
3720
3721 @Override
3722 @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "Fall through to default case is intentional")
3723 public void visitLdcInsn(Object value) {
3724 if (value instanceof Type) {
3725 Type type = (Type) value;
3726 switch (type.getSort()) {
3727 case Type.OBJECT:
3728 case Type.ARRAY:
3729 constraint.assertTypeInConstantPool();
3730 break;
3731 case Type.METHOD:
3732 constraint.assertMethodTypeInConstantPool();
3733 break;
3734 }
3735 } else if (value instanceof Handle) {
3736 constraint.assertHandleInConstantPool();
3737 } else if (value instanceof ConstantDynamic) {
3738 constraint.assertDynamicValueInConstantPool();
3739 }
3740 super.visitLdcInsn(value);
3741 }
3742
3743 @Override
3744 public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
3745 if (isInterface && opcode == Opcodes.INVOKESPECIAL) {
3746 constraint.assertDefaultMethodCall();
3747 }
3748 super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
3749 }
3750
3751 @Override
3752 public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethod, Object[] bootstrapArgument) {
3753 constraint.assertInvokeDynamic();
3754 for (Object constant : bootstrapArgument) {
3755 if (constant instanceof ConstantDynamic) {
3756 constraint.assertDynamicValueInConstantPool();
3757 }
3758 }
3759 super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethod, bootstrapArgument);
3760 }
3761
3762 @Override
3763 public void visitJumpInsn(int opcode, Label label) {
3764 if (opcode == Opcodes.JSR) {
3765 constraint.assertSubRoutine();
3766 }
3767 super.visitJumpInsn(opcode, label);
3768 }
3769 }
3770 }
3771
3772 /**
3773 * A type writer that inlines the created type into an existing class file.
3774 *
3775 * @param <U> The best known loaded type for the dynamically created type.
3776 */
3777 @HashCodeAndEqualsPlugin.Enhance
3778 public abstract static class ForInlining<U> extends Default<U> {
3779
3780 /**
3781 * Indicates that a field should be ignored.
3782 */
3783 private static final FieldVisitor IGNORE_FIELD = null;
3784
3785 /**
3786 * Indicates that a method should be ignored.
3787 */
3788 private static final MethodVisitor IGNORE_METHOD = null;
3789
3790 /**
3791 * Indicates that a record component should be ignored.
3792 */
3793 private static final RecordComponentVisitor IGNORE_RECORD_COMPONENT = null;
3794
3795 /**
3796 * Indicates that an annotation should be ignored.
3797 */
3798 private static final AnnotationVisitor IGNORE_ANNOTATION = null;
3799
3800 /**
3801 * The original type's description.
3802 */
3803 protected final TypeDescription originalType;
3804
3805 /**
3806 * The class file locator for locating the original type's class file.
3807 */
3808 protected final ClassFileLocator classFileLocator;
3809
3810 /**
3811 * Creates a new inlining type writer.
3812 *
3813 * @param instrumentedType The instrumented type to be created.
3814 * @param classFileVersion The class file specified by the user.
3815 * @param fieldPool The field pool to use.
3816 * @param recordComponentPool The record component pool to use.
3817 * @param auxiliaryTypes The explicit auxiliary types to add to the created type.
3818 * @param fields The instrumented type's declared fields.
3819 * @param methods The instrumented type's declared and virtually inherited methods.
3820 * @param instrumentedMethods The instrumented methods relevant to this type creation.
3821 * @param recordComponents The instrumented type's record components.
3822 * @param loadedTypeInitializer The loaded type initializer to apply onto the created type after loading.
3823 * @param typeInitializer The type initializer to include in the created type's type initializer.
3824 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
3825 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
3826 * @param annotationValueFilterFactory The annotation value filter factory to apply.
3827 * @param annotationRetention The annotation retention to apply.
3828 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
3829 * @param implementationContextFactory The implementation context factory to apply.
3830 * @param typeValidation Determines if a type should be explicitly validated.
3831 * @param classWriterStrategy The class writer strategy to use.
3832 * @param typePool The type pool to use for computing stack map frames, if required.
3833 * @param originalType The original type's description.
3834 * @param classFileLocator The class file locator for locating the original type's class file.
3835 */
3836 protected ForInlining(TypeDescription instrumentedType,
3837 ClassFileVersion classFileVersion,
3838 FieldPool fieldPool,
3839 RecordComponentPool recordComponentPool,
3840 List<? extends DynamicType> auxiliaryTypes,
3841 FieldList<FieldDescription.InDefinedShape> fields,
3842 MethodList<?> methods,
3843 MethodList<?> instrumentedMethods,
3844 RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
3845 LoadedTypeInitializer loadedTypeInitializer,
3846 TypeInitializer typeInitializer,
3847 TypeAttributeAppender typeAttributeAppender,
3848 AsmVisitorWrapper asmVisitorWrapper,
3849 AnnotationValueFilter.Factory annotationValueFilterFactory,
3850 AnnotationRetention annotationRetention,
3851 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
3852 Implementation.Context.Factory implementationContextFactory,
3853 TypeValidation typeValidation,
3854 ClassWriterStrategy classWriterStrategy,
3855 TypePool typePool,
3856 TypeDescription originalType,
3857 ClassFileLocator classFileLocator) {
3858 super(instrumentedType,
3859 classFileVersion,
3860 fieldPool,
3861 recordComponentPool,
3862 auxiliaryTypes,
3863 fields,
3864 methods,
3865 instrumentedMethods,
3866 recordComponents,
3867 loadedTypeInitializer,
3868 typeInitializer,
3869 typeAttributeAppender,
3870 asmVisitorWrapper,
3871 annotationValueFilterFactory,
3872 annotationRetention,
3873 auxiliaryTypeNamingStrategy,
3874 implementationContextFactory,
3875 typeValidation,
3876 classWriterStrategy,
3877 typePool);
3878 this.originalType = originalType;
3879 this.classFileLocator = classFileLocator;
3880 }
3881
3882 @Override
3883 protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
3884 try {
3885 int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS);
3886 int readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
3887 byte[] binaryRepresentation = classFileLocator.locate(originalType.getName()).resolve();
3888 dispatcher.dump(instrumentedType, true, binaryRepresentation);
3889 ClassReader classReader = OpenedClassReader.of(binaryRepresentation);
3890 ClassWriter classWriter = classWriterStrategy.resolve(writerFlags, typePool, classReader);
3891 ContextRegistry contextRegistry = new ContextRegistry();
3892 classReader.accept(writeTo(ValidatingClassVisitor.of(classWriter, typeValidation),
3893 typeInitializer,
3894 contextRegistry,
3895 writerFlags,
3896 readerFlags), readerFlags);
3897 return new UnresolvedType(classWriter.toByteArray(), contextRegistry.getAuxiliaryTypes());
3898 } catch (IOException exception) {
3899 throw new RuntimeException("The class file could not be written", exception);
3900 }
3901 }
3902
3903 /**
3904 * Creates a class visitor which weaves all changes and additions on the fly.
3905 *
3906 * @param classVisitor The class visitor to which this entry is to be written to.
3907 * @param typeInitializer The type initializer to apply.
3908 * @param contextRegistry A context registry to register the lazily created implementation context to.
3909 * @param writerFlags The writer flags being used.
3910 * @param readerFlags The reader flags being used.
3911 * @return A class visitor which is capable of applying the changes.
3912 */
3913 protected abstract ClassVisitor writeTo(ClassVisitor classVisitor,
3914 TypeInitializer typeInitializer,
3915 ContextRegistry contextRegistry,
3916 int writerFlags,
3917 int readerFlags);
3918
3919 /**
3920 * A context registry allows to extract auxiliary types from a lazily created implementation context.
3921 */
3922 protected static class ContextRegistry {
3923
3924 /**
3925 * The implementation context that is used for creating a class or {@code null} if it was not registered.
3926 */
3927 private Implementation.Context.ExtractableView implementationContext;
3928
3929 /**
3930 * Registers the implementation context.
3931 *
3932 * @param implementationContext The implementation context.
3933 */
3934 public void setImplementationContext(Implementation.Context.ExtractableView implementationContext) {
3935 this.implementationContext = implementationContext;
3936 }
3937
3938 /**
3939 * Returns the auxiliary types that were registered during class creation. This method must only be called after
3940 * a class was created.
3941 *
3942 * @return The auxiliary types that were registered during class creation
3943 */
3944 @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Lazy value definition is intended")
3945 public List<DynamicType> getAuxiliaryTypes() {
3946 return implementationContext.getAuxiliaryTypes();
3947 }
3948 }
3949
3950 /**
3951 * A default type writer that reprocesses a type completely.
3952 *
3953 * @param <V> The best known loaded type for the dynamically created type.
3954 */
3955 @HashCodeAndEqualsPlugin.Enhance
3956 protected static class WithFullProcessing<V> extends ForInlining<V> {
3957
3958 /**
3959 * The method registry to use.
3960 */
3961 private final MethodRegistry.Prepared methodRegistry;
3962
3963 /**
3964 * The implementation target factory to use.
3965 */
3966 private final Implementation.Target.Factory implementationTargetFactory;
3967
3968 /**
3969 * The method rebase resolver to use for rebasing methods.
3970 */
3971 private final MethodRebaseResolver methodRebaseResolver;
3972
3973 /**
3974 * Creates a new inlining type writer that fully reprocesses a type.
3975 *
3976 * @param instrumentedType The instrumented type to be created.
3977 * @param classFileVersion The class file specified by the user.
3978 * @param fieldPool The field pool to use.
3979 * @param recordComponentPool The record component pool to use.
3980 * @param auxiliaryTypes The explicit auxiliary types to add to the created type.
3981 * @param fields The instrumented type's declared fields.
3982 * @param methods The instrumented type's declared and virtually inherited methods.
3983 * @param instrumentedMethods The instrumented methods relevant to this type creation.
3984 * @param recordComponents The instrumented type's record components.
3985 * @param loadedTypeInitializer The loaded type initializer to apply onto the created type after loading.
3986 * @param typeInitializer The type initializer to include in the created type's type initializer.
3987 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
3988 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
3989 * @param annotationValueFilterFactory The annotation value filter factory to apply.
3990 * @param annotationRetention The annotation retention to apply.
3991 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
3992 * @param implementationContextFactory The implementation context factory to apply.
3993 * @param typeValidation Determines if a type should be explicitly validated.
3994 * @param classWriterStrategy The class writer strategy to use.
3995 * @param typePool The type pool to use for computing stack map frames, if required.
3996 * @param originalType The original type's description.
3997 * @param classFileLocator The class file locator for locating the original type's class file.
3998 * @param methodRegistry The method registry to use.
3999 * @param implementationTargetFactory The implementation target factory to use.
4000 * @param methodRebaseResolver The method rebase resolver to use for rebasing methods.
4001 */
4002 protected WithFullProcessing(TypeDescription instrumentedType,
4003 ClassFileVersion classFileVersion,
4004 FieldPool fieldPool,
4005 RecordComponentPool recordComponentPool,
4006 List<? extends DynamicType> auxiliaryTypes,
4007 FieldList<FieldDescription.InDefinedShape> fields,
4008 MethodList<?> methods, MethodList<?> instrumentedMethods,
4009 RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4010 LoadedTypeInitializer loadedTypeInitializer,
4011 TypeInitializer typeInitializer,
4012 TypeAttributeAppender typeAttributeAppender,
4013 AsmVisitorWrapper asmVisitorWrapper,
4014 AnnotationValueFilter.Factory annotationValueFilterFactory,
4015 AnnotationRetention annotationRetention,
4016 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4017 Implementation.Context.Factory implementationContextFactory,
4018 TypeValidation typeValidation,
4019 ClassWriterStrategy classWriterStrategy,
4020 TypePool typePool,
4021 TypeDescription originalType,
4022 ClassFileLocator classFileLocator,
4023 MethodRegistry.Prepared methodRegistry,
4024 Implementation.Target.Factory implementationTargetFactory,
4025 MethodRebaseResolver methodRebaseResolver) {
4026 super(instrumentedType,
4027 classFileVersion,
4028 fieldPool,
4029 recordComponentPool,
4030 auxiliaryTypes,
4031 fields,
4032 methods,
4033 instrumentedMethods,
4034 recordComponents,
4035 loadedTypeInitializer,
4036 typeInitializer,
4037 typeAttributeAppender,
4038 asmVisitorWrapper,
4039 annotationValueFilterFactory,
4040 annotationRetention,
4041 auxiliaryTypeNamingStrategy,
4042 implementationContextFactory,
4043 typeValidation,
4044 classWriterStrategy,
4045 typePool,
4046 originalType,
4047 classFileLocator);
4048 this.methodRegistry = methodRegistry;
4049 this.implementationTargetFactory = implementationTargetFactory;
4050 this.methodRebaseResolver = methodRebaseResolver;
4051 }
4052
4053 /**
4054 * {@inheritDoc}
4055 */
4056 protected ClassVisitor writeTo(ClassVisitor classVisitor, TypeInitializer typeInitializer, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
4057 classVisitor = new RedefinitionClassVisitor(classVisitor, typeInitializer, contextRegistry, writerFlags, readerFlags);
4058 return originalType.getName().equals(instrumentedType.getName())
4059 ? classVisitor
4060 : new OpenedClassRemapper(classVisitor, new SimpleRemapper(originalType.getInternalName(), instrumentedType.getInternalName()));
4061 }
4062
4063 /**
4064 * A {@link ClassRemapper} that uses the Byte Buddy-defined API version.
4065 */
4066 protected static class OpenedClassRemapper extends ClassRemapper {
4067
4068 /**
4069 * Creates a new opened class remapper.
4070 *
4071 * @param classVisitor The class visitor to wrap
4072 * @param remapper The remapper to apply.
4073 */
4074 protected OpenedClassRemapper(ClassVisitor classVisitor, Remapper remapper) {
4075 super(OpenedClassReader.ASM_API, classVisitor, remapper);
4076 }
4077 }
4078
4079 /**
4080 * An initialization handler is responsible for handling the creation of the type initializer.
4081 */
4082 protected interface InitializationHandler {
4083
4084 /**
4085 * Invoked upon completion of writing the instrumented type.
4086 *
4087 * @param classVisitor The class visitor to write any methods to.
4088 * @param implementationContext The implementation context to use.
4089 */
4090 void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext);
4091
4092 /**
4093 * An initialization handler that creates a new type initializer.
4094 */
4095 class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4096
4097 /**
4098 * Creates a new creating initialization handler.
4099 *
4100 * @param instrumentedType The instrumented type.
4101 * @param methodPool The method pool to use.
4102 * @param annotationValueFilterFactory The annotation value filter factory to use.
4103 */
4104 protected Creating(TypeDescription instrumentedType,
4105 MethodPool methodPool,
4106 AnnotationValueFilter.Factory annotationValueFilterFactory) {
4107 super(instrumentedType, methodPool, annotationValueFilterFactory);
4108 }
4109
4110 /**
4111 * {@inheritDoc}
4112 */
4113 public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4114 implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
4115 }
4116 }
4117
4118 /**
4119 * An initialization handler that appends code to a previously visited type initializer.
4120 */
4121 abstract class Appending extends MethodVisitor implements InitializationHandler, TypeInitializer.Drain {
4122
4123 /**
4124 * The instrumented type.
4125 */
4126 protected final TypeDescription instrumentedType;
4127
4128 /**
4129 * The method pool record for the type initializer.
4130 */
4131 protected final MethodPool.Record record;
4132
4133 /**
4134 * The used annotation value filter factory.
4135 */
4136 protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4137
4138 /**
4139 * The frame writer to use.
4140 */
4141 protected final FrameWriter frameWriter;
4142
4143 /**
4144 * The currently recorded stack size.
4145 */
4146 protected int stackSize;
4147
4148 /**
4149 * The currently recorded local variable length.
4150 */
4151 protected int localVariableLength;
4152
4153 /**
4154 * Creates a new appending initialization handler.
4155 *
4156 * @param methodVisitor The underlying method visitor.
4157 * @param instrumentedType The instrumented type.
4158 * @param record The method pool record for the type initializer.
4159 * @param annotationValueFilterFactory The used annotation value filter factory.
4160 * @param requireFrames {@code true} if the visitor is required to add frames.
4161 * @param expandFrames {@code true} if the visitor is required to expand any added frame.
4162 */
4163 protected Appending(MethodVisitor methodVisitor,
4164 TypeDescription instrumentedType,
4165 MethodPool.Record record,
4166 AnnotationValueFilter.Factory annotationValueFilterFactory,
4167 boolean requireFrames,
4168 boolean expandFrames) {
4169 super(OpenedClassReader.ASM_API, methodVisitor);
4170 this.instrumentedType = instrumentedType;
4171 this.record = record;
4172 this.annotationValueFilterFactory = annotationValueFilterFactory;
4173 if (!requireFrames) {
4174 frameWriter = FrameWriter.NoOp.INSTANCE;
4175 } else if (expandFrames) {
4176 frameWriter = FrameWriter.Expanding.INSTANCE;
4177 } else {
4178 frameWriter = new FrameWriter.Active();
4179 }
4180 }
4181
4182 /**
4183 * Resolves an initialization handler.
4184 *
4185 * @param enabled {@code true} if the implementation context is enabled, i.e. any {@link TypeInitializer} might be active.
4186 * @param methodVisitor The delegation method visitor.
4187 * @param instrumentedType The instrumented type.
4188 * @param methodPool The method pool to use.
4189 * @param annotationValueFilterFactory The annotation value filter factory to use.
4190 * @param requireFrames {@code true} if frames must be computed.
4191 * @param expandFrames {@code true} if frames must be expanded.
4192 * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4193 */
4194 protected static InitializationHandler of(boolean enabled,
4195 MethodVisitor methodVisitor,
4196 TypeDescription instrumentedType,
4197 MethodPool methodPool,
4198 AnnotationValueFilter.Factory annotationValueFilterFactory,
4199 boolean requireFrames,
4200 boolean expandFrames) {
4201 return enabled
4202 ? withDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames)
4203 : withoutDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames);
4204 }
4205
4206 /**
4207 * Resolves an initialization handler with a drain.
4208 *
4209 * @param methodVisitor The delegation method visitor.
4210 * @param instrumentedType The instrumented type.
4211 * @param methodPool The method pool to use.
4212 * @param annotationValueFilterFactory The annotation value filter factory to use.
4213 * @param requireFrames {@code true} if frames must be computed.
4214 * @param expandFrames {@code true} if frames must be expanded.
4215 * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4216 */
4217 private static WithDrain withDrain(MethodVisitor methodVisitor,
4218 TypeDescription instrumentedType,
4219 MethodPool methodPool,
4220 AnnotationValueFilter.Factory annotationValueFilterFactory,
4221 boolean requireFrames,
4222 boolean expandFrames) {
4223 MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
4224 return record.getSort().isImplemented()
4225 ? new WithDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4226 : new WithDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4227 }
4228
4229 /**
4230 * Resolves an initialization handler without a drain.
4231 *
4232 * @param methodVisitor The delegation method visitor.
4233 * @param instrumentedType The instrumented type.
4234 * @param methodPool The method pool to use.
4235 * @param annotationValueFilterFactory The annotation value filter factory to use.
4236 * @param requireFrames {@code true} if frames must be computed.
4237 * @param expandFrames {@code true} if frames must be expanded.
4238 * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4239 */
4240 private static WithoutDrain withoutDrain(MethodVisitor methodVisitor,
4241 TypeDescription instrumentedType,
4242 MethodPool methodPool,
4243 AnnotationValueFilter.Factory annotationValueFilterFactory,
4244 boolean requireFrames,
4245 boolean expandFrames) {
4246 MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
4247 return record.getSort().isImplemented()
4248 ? new WithoutDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4249 : new WithoutDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory);
4250 }
4251
4252 @Override
4253 public void visitCode() {
4254 record.applyAttributes(mv, annotationValueFilterFactory);
4255 super.visitCode();
4256 onStart();
4257 }
4258
4259 /**
4260 * Invoked after the user code was visited.
4261 */
4262 protected abstract void onStart();
4263
4264 @Override
4265 public void visitFrame(int type, int localVariableLength, Object[] localVariable, int stackSize, Object[] stack) {
4266 super.visitFrame(type, localVariableLength, localVariable, stackSize, stack);
4267 frameWriter.onFrame(type, localVariableLength);
4268 }
4269
4270 @Override
4271 public void visitMaxs(int stackSize, int localVariableLength) {
4272 this.stackSize = stackSize;
4273 this.localVariableLength = localVariableLength;
4274 }
4275
4276 @Override
4277 public abstract void visitEnd();
4278
4279 /**
4280 * {@inheritDoc}
4281 */
4282 public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
4283 ByteCodeAppender.Size size = typeInitializer.apply(mv, implementationContext, new MethodDescription.Latent.TypeInitializer(instrumentedType));
4284 stackSize = Math.max(stackSize, size.getOperandStackSize());
4285 localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
4286 onComplete(implementationContext);
4287 }
4288
4289 /**
4290 * Invoked upon completion of writing the type initializer.
4291 *
4292 * @param implementationContext The implementation context to use.
4293 */
4294 protected abstract void onComplete(Implementation.Context implementationContext);
4295
4296 /**
4297 * {@inheritDoc}
4298 */
4299 public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4300 implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
4301 mv.visitMaxs(stackSize, localVariableLength);
4302 mv.visitEnd();
4303 }
4304
4305 /**
4306 * A frame writer is responsible for adding empty frames on jump instructions.
4307 */
4308 protected interface FrameWriter {
4309
4310 /**
4311 * An empty array.
4312 */
4313 Object[] EMPTY = new Object[0];
4314
4315 /**
4316 * Informs this frame writer of an observed frame.
4317 *
4318 * @param type The frame type.
4319 * @param localVariableLength The length of the local variables array.
4320 */
4321 void onFrame(int type, int localVariableLength);
4322
4323 /**
4324 * Emits an empty frame.
4325 *
4326 * @param methodVisitor The method visitor to write the frame to.
4327 */
4328 void emitFrame(MethodVisitor methodVisitor);
4329
4330 /**
4331 * A non-operational frame writer.
4332 */
4333 enum NoOp implements FrameWriter {
4334
4335 /**
4336 * The singleton instance.
4337 */
4338 INSTANCE;
4339
4340 /**
4341 * {@inheritDoc}
4342 */
4343 public void onFrame(int type, int localVariableLength) {
4344 /* do nothing */
4345 }
4346
4347 /**
4348 * {@inheritDoc}
4349 */
4350 public void emitFrame(MethodVisitor methodVisitor) {
4351 /* do nothing */
4352 }
4353 }
4354
4355 /**
4356 * A frame writer that creates an expanded frame.
4357 */
4358 enum Expanding implements FrameWriter {
4359
4360 /**
4361 * The singleton instance.
4362 */
4363 INSTANCE;
4364
4365 /**
4366 * {@inheritDoc}
4367 */
4368 public void onFrame(int type, int localVariableLength) {
4369 /* do nothing */
4370 }
4371
4372 /**
4373 * {@inheritDoc}
4374 */
4375 public void emitFrame(MethodVisitor methodVisitor) {
4376 methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
4377 }
4378 }
4379
4380 /**
4381 * An active frame writer that creates the most efficient frame.
4382 */
4383 class Active implements FrameWriter {
4384
4385 /**
4386 * The current length of the current local variable array.
4387 */
4388 private int currentLocalVariableLength;
4389
4390 /**
4391 * {@inheritDoc}
4392 */
4393 public void onFrame(int type, int localVariableLength) {
4394 switch (type) {
4395 case Opcodes.F_SAME:
4396 case Opcodes.F_SAME1:
4397 break;
4398 case Opcodes.F_APPEND:
4399 currentLocalVariableLength += localVariableLength;
4400 break;
4401 case Opcodes.F_CHOP:
4402 currentLocalVariableLength -= localVariableLength;
4403 break;
4404 case Opcodes.F_NEW:
4405 case Opcodes.F_FULL:
4406 currentLocalVariableLength = localVariableLength;
4407 break;
4408 default:
4409 throw new IllegalStateException("Unexpected frame type: " + type);
4410 }
4411 }
4412
4413 /**
4414 * {@inheritDoc}
4415 */
4416 public void emitFrame(MethodVisitor methodVisitor) {
4417 if (currentLocalVariableLength == 0) {
4418 methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
4419 } else if (currentLocalVariableLength > 3) {
4420 methodVisitor.visitFrame(Opcodes.F_FULL, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
4421 } else {
4422 methodVisitor.visitFrame(Opcodes.F_CHOP, currentLocalVariableLength, EMPTY, EMPTY.length, EMPTY);
4423 }
4424 currentLocalVariableLength = 0;
4425 }
4426 }
4427 }
4428
4429 /**
4430 * An initialization handler that appends code to a previously visited type initializer without allowing active
4431 * {@link TypeInitializer} registrations.
4432 */
4433 protected abstract static class WithoutDrain extends Appending {
4434
4435 /**
4436 * Creates a new appending initialization handler without a drain.
4437 *
4438 * @param methodVisitor The underlying method visitor.
4439 * @param instrumentedType The instrumented type.
4440 * @param record The method pool record for the type initializer.
4441 * @param annotationValueFilterFactory The used annotation value filter factory.
4442 * @param requireFrames {@code true} if the visitor is required to add frames.
4443 * @param expandFrames {@code true} if the visitor is required to expand any added frame.
4444 */
4445 protected WithoutDrain(MethodVisitor methodVisitor,
4446 TypeDescription instrumentedType,
4447 MethodPool.Record record,
4448 AnnotationValueFilter.Factory annotationValueFilterFactory,
4449 boolean requireFrames,
4450 boolean expandFrames) {
4451 super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4452 }
4453
4454 @Override
4455 protected void onStart() {
4456 /* do nothing */
4457 }
4458
4459 @Override
4460 public void visitEnd() {
4461 /* do nothing */
4462 }
4463
4464 /**
4465 * An initialization handler that appends code to a previously visited type initializer without allowing active
4466 * {@link TypeInitializer} registrations and without an active record.
4467 */
4468 protected static class WithoutActiveRecord extends WithoutDrain {
4469
4470 /**
4471 * Creates a new appending initialization handler without a drain and without an active record.
4472 *
4473 * @param methodVisitor The underlying method visitor.
4474 * @param instrumentedType The instrumented type.
4475 * @param record The method pool record for the type initializer.
4476 * @param annotationValueFilterFactory The used annotation value filter factory.
4477 */
4478 protected WithoutActiveRecord(MethodVisitor methodVisitor,
4479 TypeDescription instrumentedType,
4480 MethodPool.Record record,
4481 AnnotationValueFilter.Factory annotationValueFilterFactory) {
4482 super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, false, false);
4483 }
4484
4485 @Override
4486 protected void onComplete(Implementation.Context implementationContext) {
4487 /* do nothing */
4488 }
4489 }
4490
4491 /**
4492 * An initialization handler that appends code to a previously visited type initializer without allowing active
4493 * {@link TypeInitializer} registrations and with an active record.
4494 */
4495 protected static class WithActiveRecord extends WithoutDrain {
4496
4497 /**
4498 * The label that indicates the beginning of the active record.
4499 */
4500 private final Label label;
4501
4502 /**
4503 * Creates a new appending initialization handler without a drain and with an active record.
4504 *
4505 * @param methodVisitor The underlying method visitor.
4506 * @param instrumentedType The instrumented type.
4507 * @param record The method pool record for the type initializer.
4508 * @param annotationValueFilterFactory The used annotation value filter factory.
4509 * @param requireFrames {@code true} if the visitor is required to add frames.
4510 * @param expandFrames {@code true} if the visitor is required to expand any added frame.
4511 */
4512 protected WithActiveRecord(MethodVisitor methodVisitor,
4513 TypeDescription instrumentedType,
4514 MethodPool.Record record,
4515 AnnotationValueFilter.Factory annotationValueFilterFactory,
4516 boolean requireFrames,
4517 boolean expandFrames) {
4518 super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4519 label = new Label();
4520 }
4521
4522 @Override
4523 public void visitInsn(int opcode) {
4524 if (opcode == Opcodes.RETURN) {
4525 mv.visitJumpInsn(Opcodes.GOTO, label);
4526 } else {
4527 super.visitInsn(opcode);
4528 }
4529 }
4530
4531 @Override
4532 protected void onComplete(Implementation.Context implementationContext) {
4533 mv.visitLabel(label);
4534 frameWriter.emitFrame(mv);
4535 ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
4536 stackSize = Math.max(stackSize, size.getOperandStackSize());
4537 localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
4538 }
4539
4540 }
4541 }
4542
4543 /**
4544 * An initialization handler that appends code to a previously visited type initializer with allowing active
4545 * {@link TypeInitializer} registrations.
4546 */
4547 protected abstract static class WithDrain extends Appending {
4548
4549 /**
4550 * A label marking the beginning of the appended code.
4551 */
4552 protected final Label appended;
4553
4554 /**
4555 * A label marking the beginning og the original type initializer's code.
4556 */
4557 protected final Label original;
4558
4559 /**
4560 * Creates a new appending initialization handler with a drain.
4561 *
4562 * @param methodVisitor The underlying method visitor.
4563 * @param instrumentedType The instrumented type.
4564 * @param record The method pool record for the type initializer.
4565 * @param annotationValueFilterFactory The used annotation value filter factory.
4566 * @param requireFrames {@code true} if the visitor is required to add frames.
4567 * @param expandFrames {@code true} if the visitor is required to expand any added frame.
4568 */
4569 protected WithDrain(MethodVisitor methodVisitor,
4570 TypeDescription instrumentedType,
4571 MethodPool.Record record,
4572 AnnotationValueFilter.Factory annotationValueFilterFactory,
4573 boolean requireFrames,
4574 boolean expandFrames) {
4575 super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4576 appended = new Label();
4577 original = new Label();
4578 }
4579
4580 @Override
4581 protected void onStart() {
4582 mv.visitJumpInsn(Opcodes.GOTO, appended);
4583 mv.visitLabel(original);
4584 frameWriter.emitFrame(mv);
4585 }
4586
4587 @Override
4588 public void visitEnd() {
4589 mv.visitLabel(appended);
4590 frameWriter.emitFrame(mv);
4591 }
4592
4593 @Override
4594 protected void onComplete(Implementation.Context implementationContext) {
4595 mv.visitJumpInsn(Opcodes.GOTO, original);
4596 onAfterComplete(implementationContext);
4597 }
4598
4599 /**
4600 * Invoked after completion of writing the type initializer.
4601 *
4602 * @param implementationContext The implementation context to use.
4603 */
4604 protected abstract void onAfterComplete(Implementation.Context implementationContext);
4605
4606 /**
4607 * A code appending initialization handler with a drain that does not apply an explicit record.
4608 */
4609 protected static class WithoutActiveRecord extends WithDrain {
4610
4611 /**
4612 * Creates a new appending initialization handler with a drain and without an active record.
4613 *
4614 * @param methodVisitor The underlying method visitor.
4615 * @param instrumentedType The instrumented type.
4616 * @param record The method pool record for the type initializer.
4617 * @param annotationValueFilterFactory The used annotation value filter factory.
4618 * @param requireFrames {@code true} if the visitor is required to add frames.
4619 * @param expandFrames {@code true} if the visitor is required to expand any added frame.
4620 */
4621 protected WithoutActiveRecord(MethodVisitor methodVisitor,
4622 TypeDescription instrumentedType,
4623 MethodPool.Record record,
4624 AnnotationValueFilter.Factory annotationValueFilterFactory,
4625 boolean requireFrames,
4626 boolean expandFrames) {
4627 super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4628 }
4629
4630 @Override
4631 protected void onAfterComplete(Implementation.Context implementationContext) {
4632 /* do nothing */
4633 }
4634 }
4635
4636 /**
4637 * A code appending initialization handler with a drain that applies an explicit record.
4638 */
4639 protected static class WithActiveRecord extends WithDrain {
4640
4641 /**
4642 * A label indicating the beginning of the record's code.
4643 */
4644 private final Label label;
4645
4646 /**
4647 * Creates a new appending initialization handler with a drain and with an active record.
4648 *
4649 * @param methodVisitor The underlying method visitor.
4650 * @param instrumentedType The instrumented type.
4651 * @param record The method pool record for the type initializer.
4652 * @param annotationValueFilterFactory The used annotation value filter factory.
4653 * @param requireFrames {@code true} if the visitor is required to add frames.
4654 * @param expandFrames {@code true} if the visitor is required to expand any added frame.
4655 */
4656 protected WithActiveRecord(MethodVisitor methodVisitor,
4657 TypeDescription instrumentedType,
4658 MethodPool.Record record,
4659 AnnotationValueFilter.Factory annotationValueFilterFactory,
4660 boolean requireFrames,
4661 boolean expandFrames) {
4662 super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4663 label = new Label();
4664 }
4665
4666 @Override
4667 public void visitInsn(int opcode) {
4668 if (opcode == Opcodes.RETURN) {
4669 mv.visitJumpInsn(Opcodes.GOTO, label);
4670 } else {
4671 super.visitInsn(opcode);
4672 }
4673 }
4674
4675 @Override
4676 protected void onAfterComplete(Implementation.Context implementationContext) {
4677 mv.visitLabel(label);
4678 frameWriter.emitFrame(mv);
4679 ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
4680 stackSize = Math.max(stackSize, size.getOperandStackSize());
4681 localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
4682 }
4683 }
4684 }
4685 }
4686 }
4687
4688 /**
4689 * A class visitor which is capable of applying a redefinition of an existing class file.
4690 */
4691 @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM")
4692 protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
4693
4694 /**
4695 * The type initializer to apply.
4696 */
4697 private final TypeInitializer typeInitializer;
4698
4699 /**
4700 * A context registry to register the lazily created implementation context to.
4701 */
4702 private final ContextRegistry contextRegistry;
4703
4704 /**
4705 * The writer flags being used.
4706 */
4707 private final int writerFlags;
4708
4709 /**
4710 * The reader flags being used.
4711 */
4712 private final int readerFlags;
4713
4714 /**
4715 * A mapping of fields to write by their names.
4716 */
4717 private final LinkedHashMap<String, FieldDescription> declarableFields;
4718
4719 /**
4720 * A mapping of methods to write by a concatenation of internal name and descriptor.
4721 */
4722 private final LinkedHashMap<String, MethodDescription> declarableMethods;
4723
4724 /**
4725 * A mapping of record components to write by their names.
4726 */
4727 private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
4728
4729 /**
4730 * A set of internal names of all nest members not yet defined by this type. If this type is not a nest host, this set is empty.
4731 */
4732 private final Set<String> nestMembers;
4733
4734 /**
4735 * A mapping of the internal names of all declared types to their description.
4736 */
4737 private final LinkedHashMap<String, TypeDescription> declaredTypes;
4738
4739 /**
4740 * A list of internal names of permitted subclasses to include.
4741 */
4742 private final List<String> permittedSubclasses;
4743
4744 /**
4745 * The method pool to use or {@code null} if the pool was not yet initialized.
4746 */
4747 private MethodPool methodPool;
4748
4749 /**
4750 * The initialization handler to use or {@code null} if the handler was not yet initialized.
4751 */
4752 private InitializationHandler initializationHandler;
4753
4754 /**
4755 * The implementation context for this class creation or {@code null} if it was not yet created.
4756 */
4757 private Implementation.Context.ExtractableView implementationContext;
4758
4759 /**
4760 * {@code true} if the modifiers for deprecation should be retained.
4761 */
4762 private boolean retainDeprecationModifiers;
4763
4764 /**
4765 * Creates a class visitor which is capable of redefining an existent class on the fly.
4766 *
4767 * @param classVisitor The underlying class visitor to which writes are delegated.
4768 * @param typeInitializer The type initializer to apply.
4769 * @param contextRegistry A context registry to register the lazily created implementation context to.
4770 * @param writerFlags The writer flags being used.
4771 * @param readerFlags The reader flags being used.
4772 */
4773 protected RedefinitionClassVisitor(ClassVisitor classVisitor,
4774 TypeInitializer typeInitializer,
4775 ContextRegistry contextRegistry,
4776 int writerFlags,
4777 int readerFlags) {
4778 super(OpenedClassReader.ASM_API, classVisitor);
4779 this.typeInitializer = typeInitializer;
4780 this.contextRegistry = contextRegistry;
4781 this.writerFlags = writerFlags;
4782 this.readerFlags = readerFlags;
4783 declarableFields = new LinkedHashMap<String, FieldDescription>();
4784 for (FieldDescription fieldDescription : fields) {
4785 declarableFields.put(fieldDescription.getInternalName() + fieldDescription.getDescriptor(), fieldDescription);
4786 }
4787 declarableMethods = new LinkedHashMap<String, MethodDescription>();
4788 for (MethodDescription methodDescription : instrumentedMethods) {
4789 declarableMethods.put(methodDescription.getInternalName() + methodDescription.getDescriptor(), methodDescription);
4790 }
4791 declarableRecordComponents = new LinkedHashMap<String, RecordComponentDescription>();
4792 for (RecordComponentDescription recordComponentDescription : recordComponents) {
4793 declarableRecordComponents.put(recordComponentDescription.getActualName(), recordComponentDescription);
4794 }
4795 if (instrumentedType.isNestHost()) {
4796 nestMembers = new LinkedHashSet<String>();
4797 for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
4798 nestMembers.add(typeDescription.getInternalName());
4799 }
4800 } else {
4801 nestMembers = Collections.emptySet();
4802 }
4803 declaredTypes = new LinkedHashMap<String, TypeDescription>();
4804 for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
4805 declaredTypes.put(typeDescription.getInternalName(), typeDescription);
4806 }
4807 permittedSubclasses = new ArrayList<String>(instrumentedType.getPermittedSubclasses().size());
4808 for (TypeDescription typeDescription : instrumentedType.getPermittedSubclasses()) {
4809 permittedSubclasses.add(typeDescription.getInternalName());
4810 }
4811 }
4812
4813 @Override
4814 public void visit(int classFileVersionNumber,
4815 int modifiers,
4816 String internalName,
4817 String genericSignature,
4818 String superClassInternalName,
4819 String[] interfaceTypeInternalName) {
4820 ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
4821 methodPool = methodRegistry.compile(implementationTargetFactory, classFileVersion);
4822 initializationHandler = new InitializationHandler.Creating(instrumentedType, methodPool, annotationValueFilterFactory);
4823 implementationContext = implementationContextFactory.make(instrumentedType,
4824 auxiliaryTypeNamingStrategy,
4825 typeInitializer,
4826 classFileVersion,
4827 WithFullProcessing.this.classFileVersion);
4828 retainDeprecationModifiers = classFileVersion.isLessThan(ClassFileVersion.JAVA_V5);
4829 contextRegistry.setImplementationContext(implementationContext);
4830 cv = asmVisitorWrapper.wrap(instrumentedType,
4831 cv,
4832 implementationContext,
4833 typePool,
4834 fields,
4835 methods,
4836 writerFlags,
4837 readerFlags);
4838 cv.visit(classFileVersionNumber,
4839 instrumentedType.getActualModifiers((modifiers & Opcodes.ACC_SUPER) != 0 && !instrumentedType.isInterface())
4840 | resolveDeprecationModifiers(modifiers)
4841 // Anonymous types might not preserve their class file's final modifier via their inner class modifier.
4842 | (((modifiers & Opcodes.ACC_FINAL) != 0 && instrumentedType.isAnonymousType()) ? Opcodes.ACC_FINAL : 0),
4843 instrumentedType.getInternalName(),
4844 TypeDescription.AbstractBase.RAW_TYPES
4845 ? genericSignature
4846 : instrumentedType.getGenericSignature(),
4847 instrumentedType.getSuperClass() == null
4848 ? (instrumentedType.isInterface() ? TypeDescription.OBJECT.getInternalName() : NO_REFERENCE)
4849 : instrumentedType.getSuperClass().asErasure().getInternalName(),
4850 instrumentedType.getInterfaces().asErasures().toInternalNames());
4851 }
4852
4853 @Override
4854 protected void onVisitNestHost(String nestHost) {
4855 onNestHost();
4856 }
4857
4858 @Override
4859 protected void onNestHost() {
4860 if (!instrumentedType.isNestHost()) {
4861 cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
4862 }
4863 }
4864
4865 @Override
4866 protected void onVisitPermittedSubclass(String permittedSubclass) {
4867 if (permittedSubclasses.remove(permittedSubclass)) {
4868 cv.visitPermittedSubclass(permittedSubclass);
4869 }
4870 }
4871
4872 @Override
4873 protected void onAfterPermittedSubclasses() {
4874 for (String permittedSubclass : permittedSubclasses) {
4875 cv.visitPermittedSubclass(permittedSubclass);
4876 }
4877 }
4878
4879 @Override
4880 protected void onVisitOuterClass(String owner, String name, String descriptor) {
4881 try { // The Groovy compiler often gets this attribute wrong such that this safety just retains it.
4882 onOuterType();
4883 } catch (Throwable ignored) {
4884 cv.visitOuterClass(owner, name, descriptor);
4885 }
4886 }
4887
4888 @Override
4889 protected void onOuterType() {
4890 MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
4891 if (enclosingMethod != null) {
4892 cv.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
4893 enclosingMethod.getInternalName(),
4894 enclosingMethod.getDescriptor());
4895 } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
4896 cv.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
4897 }
4898 }
4899
4900 @Override
4901 protected void onAfterAttributes() {
4902 typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
4903 }
4904
4905 @Override
4906 protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
4907 return annotationRetention.isEnabled()
4908 ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
4909 : IGNORE_ANNOTATION;
4910 }
4911
4912 @Override
4913 protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
4914 return annotationRetention.isEnabled()
4915 ? cv.visitAnnotation(descriptor, visible)
4916 : IGNORE_ANNOTATION;
4917 }
4918
4919 @Override
4920 protected RecordComponentVisitor onVisitRecordComponent(String name, String descriptor, String genericSignature) {
4921 RecordComponentDescription recordComponentDescription = declarableRecordComponents.remove(name);
4922 if (recordComponentDescription != null) {
4923 RecordComponentPool.Record record = recordComponentPool.target(recordComponentDescription);
4924 if (!record.isImplicit()) {
4925 return redefine(record, genericSignature);
4926 }
4927 }
4928 return cv.visitRecordComponent(name, descriptor, genericSignature);
4929 }
4930
4931 /**
4932 * Redefines a record component using the given explicit record component pool record.
4933 *
4934 * @param record The record component pool record to apply during visitation of the existing record.
4935 * @param genericSignature The record component's original generic signature which can be {@code null}.
4936 * @return A record component visitor for visiting the existing record component definition.
4937 */
4938 protected RecordComponentVisitor redefine(RecordComponentPool.Record record, String genericSignature) {
4939 RecordComponentDescription recordComponentDescription = record.getRecordComponent();
4940 RecordComponentVisitor recordComponentVisitor = cv.visitRecordComponent(recordComponentDescription.getActualName(),
4941 recordComponentDescription.getDescriptor(),
4942 TypeDescription.AbstractBase.RAW_TYPES
4943 ? genericSignature
4944 : recordComponentDescription.getGenericSignature());
4945 return recordComponentVisitor == null
4946 ? IGNORE_RECORD_COMPONENT
4947 : new AttributeObtainingRecordComponentVisitor(recordComponentVisitor, record);
4948 }
4949
4950 @Override
4951 protected void onAfterRecordComponents() {
4952 for (RecordComponentDescription recordComponent : declarableRecordComponents.values()) {
4953 recordComponentPool.target(recordComponent).apply(cv, annotationValueFilterFactory);
4954 }
4955 }
4956
4957 @Override
4958 protected FieldVisitor onVisitField(int modifiers,
4959 String internalName,
4960 String descriptor,
4961 String genericSignature,
4962 Object defaultValue) {
4963 FieldDescription fieldDescription = declarableFields.remove(internalName + descriptor);
4964 if (fieldDescription != null) {
4965 FieldPool.Record record = fieldPool.target(fieldDescription);
4966 if (!record.isImplicit()) {
4967 return redefine(record, defaultValue, modifiers, genericSignature);
4968 }
4969 }
4970 return cv.visitField(modifiers, internalName, descriptor, genericSignature, defaultValue);
4971 }
4972
4973 /**
4974 * Redefines a field using the given explicit field pool record and default value.
4975 *
4976 * @param record The field pool value to apply during visitation of the existing field.
4977 * @param defaultValue The default value to write onto the field which might be {@code null}.
4978 * @param modifiers The original modifiers of the transformed field.
4979 * @param genericSignature The field's original generic signature which can be {@code null}.
4980 * @return A field visitor for visiting the existing field definition.
4981 */
4982 protected FieldVisitor redefine(FieldPool.Record record, Object defaultValue, int modifiers, String genericSignature) {
4983 FieldDescription instrumentedField = record.getField();
4984 FieldVisitor fieldVisitor = cv.visitField(instrumentedField.getActualModifiers() | resolveDeprecationModifiers(modifiers),
4985 instrumentedField.getInternalName(),
4986 instrumentedField.getDescriptor(),
4987 TypeDescription.AbstractBase.RAW_TYPES
4988 ? genericSignature
4989 : instrumentedField.getGenericSignature(),
4990 record.resolveDefault(defaultValue));
4991 return fieldVisitor == null
4992 ? IGNORE_FIELD
4993 : new AttributeObtainingFieldVisitor(fieldVisitor, record);
4994 }
4995
4996 @Override
4997 protected MethodVisitor onVisitMethod(int modifiers,
4998 String internalName,
4999 String descriptor,
5000 String genericSignature,
5001 String[] exceptionName) {
5002 if (internalName.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
5003 MethodVisitor methodVisitor = cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName);
5004 return methodVisitor == null
5005 ? IGNORE_METHOD
5006 : (MethodVisitor) (initializationHandler = InitializationHandler.Appending.of(implementationContext.isEnabled(),
5007 methodVisitor,
5008 instrumentedType,
5009 methodPool,
5010 annotationValueFilterFactory,
5011 (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V6),
5012 (readerFlags & ClassReader.EXPAND_FRAMES) != 0));
5013 } else {
5014 MethodDescription methodDescription = declarableMethods.remove(internalName + descriptor);
5015 return methodDescription == null
5016 ? cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName)
5017 : redefine(methodDescription, (modifiers & Opcodes.ACC_ABSTRACT) != 0, modifiers, genericSignature);
5018 }
5019 }
5020
5021 /**
5022 * Redefines a given method if this is required by looking up a potential implementation from the
5023 * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool}.
5024 *
5025 * @param methodDescription The method being considered for redefinition.
5026 * @param abstractOrigin {@code true} if the original method is abstract, i.e. there is no implementation to preserve.
5027 * @param modifiers The original modifiers of the transformed method.
5028 * @param genericSignature The method's original generic signature which can be {@code null}.
5029 * @return A method visitor which is capable of consuming the original method.
5030 */
5031 protected MethodVisitor redefine(MethodDescription methodDescription, boolean abstractOrigin, int modifiers, String genericSignature) {
5032 MethodPool.Record record = methodPool.target(methodDescription);
5033 if (!record.getSort().isDefined()) {
5034 return cv.visitMethod(methodDescription.getActualModifiers() | resolveDeprecationModifiers(modifiers),
5035 methodDescription.getInternalName(),
5036 methodDescription.getDescriptor(),
5037 TypeDescription.AbstractBase.RAW_TYPES
5038 ? genericSignature
5039 : methodDescription.getGenericSignature(),
5040 methodDescription.getExceptionTypes().asErasures().toInternalNames());
5041 }
5042 MethodDescription implementedMethod = record.getMethod();
5043 MethodVisitor methodVisitor = cv.visitMethod(ModifierContributor.Resolver
5044 .of(Collections.singleton(record.getVisibility()))
5045 .resolve(implementedMethod.getActualModifiers(record.getSort().isImplemented())) | resolveDeprecationModifiers(modifiers),
5046 implementedMethod.getInternalName(),
5047 implementedMethod.getDescriptor(),
5048 TypeDescription.AbstractBase.RAW_TYPES
5049 ? genericSignature
5050 : implementedMethod.getGenericSignature(),
5051 implementedMethod.getExceptionTypes().asErasures().toInternalNames());
5052 if (methodVisitor == null) {
5053 return IGNORE_METHOD;
5054 } else if (abstractOrigin) {
5055 return new AttributeObtainingMethodVisitor(methodVisitor, record);
5056 } else if (methodDescription.isNative()) {
5057 MethodRebaseResolver.Resolution resolution = methodRebaseResolver.resolve(implementedMethod.asDefined());
5058 if (resolution.isRebased()) {
5059 MethodVisitor rebasedMethodVisitor = super.visitMethod(resolution.getResolvedMethod().getActualModifiers()
5060 | resolveDeprecationModifiers(modifiers),
5061 resolution.getResolvedMethod().getInternalName(),
5062 resolution.getResolvedMethod().getDescriptor(),
5063 TypeDescription.AbstractBase.RAW_TYPES
5064 ? genericSignature
5065 : implementedMethod.getGenericSignature(),
5066 resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
5067 if (rebasedMethodVisitor != null) {
5068 rebasedMethodVisitor.visitEnd();
5069 }
5070 }
5071 return new AttributeObtainingMethodVisitor(methodVisitor, record);
5072 } else {
5073 return new CodePreservingMethodVisitor(methodVisitor, record, methodRebaseResolver.resolve(implementedMethod.asDefined()));
5074 }
5075 }
5076
5077 @Override
5078 protected void onVisitInnerClass(String internalName, String outerName, String innerName, int modifiers) {
5079 if (!internalName.equals(instrumentedType.getInternalName())) {
5080 TypeDescription declaredType = declaredTypes.remove(internalName);
5081 if (declaredType == null) {
5082 cv.visitInnerClass(internalName, outerName, innerName, modifiers);
5083 } else {
5084 cv.visitInnerClass(internalName,
5085 // The second condition is added to retain the structure of some Java 6 compiled classes
5086 declaredType.isMemberType() || outerName != null && innerName == null && declaredType.isAnonymousType()
5087 ? instrumentedType.getInternalName()
5088 : NO_REFERENCE,
5089 declaredType.isAnonymousType()
5090 ? NO_REFERENCE
5091 : declaredType.getSimpleName(),
5092 declaredType.getModifiers());
5093 }
5094 }
5095 }
5096
5097 @Override
5098 protected void onVisitNestMember(String nestMember) {
5099 if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
5100 cv.visitNestMember(nestMember);
5101 }
5102 }
5103
5104 @Override
5105 protected void onVisitEnd() {
5106 for (FieldDescription fieldDescription : declarableFields.values()) {
5107 fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
5108 }
5109 for (MethodDescription methodDescription : declarableMethods.values()) {
5110 methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
5111 }
5112 initializationHandler.complete(cv, implementationContext);
5113 TypeDescription declaringType = instrumentedType.getDeclaringType();
5114 if (declaringType != null) {
5115 cv.visitInnerClass(instrumentedType.getInternalName(),
5116 declaringType.getInternalName(),
5117 instrumentedType.getSimpleName(),
5118 instrumentedType.getModifiers());
5119 } else if (instrumentedType.isLocalType()) {
5120 cv.visitInnerClass(instrumentedType.getInternalName(),
5121 NO_REFERENCE,
5122 instrumentedType.getSimpleName(),
5123 instrumentedType.getModifiers());
5124 } else if (instrumentedType.isAnonymousType()) {
5125 cv.visitInnerClass(instrumentedType.getInternalName(),
5126 NO_REFERENCE,
5127 NO_REFERENCE,
5128 instrumentedType.getModifiers());
5129 }
5130 for (TypeDescription typeDescription : declaredTypes.values()) {
5131 cv.visitInnerClass(typeDescription.getInternalName(),
5132 typeDescription.isMemberType()
5133 ? instrumentedType.getInternalName()
5134 : NO_REFERENCE,
5135 typeDescription.isAnonymousType()
5136 ? NO_REFERENCE
5137 : typeDescription.getSimpleName(),
5138 typeDescription.getModifiers());
5139 }
5140 cv.visitEnd();
5141 }
5142
5143 /**
5144 * Returns {@link Opcodes#ACC_DEPRECATED} if the current class file version only represents deprecated methods using modifiers
5145 * that are not exposed in the type description API what is true for class files before Java 5 and if the supplied modifiers indicate
5146 * deprecation.
5147 *
5148 * @param modifiers The original modifiers.
5149 * @return {@link Opcodes#ACC_DEPRECATED} if the supplied modifiers imply deprecation.
5150 */
5151 private int resolveDeprecationModifiers(int modifiers) {
5152 return retainDeprecationModifiers && (modifiers & Opcodes.ACC_DEPRECATED) != 0
5153 ? Opcodes.ACC_DEPRECATED
5154 : ModifierContributor.EMPTY_MASK;
5155 }
5156
5157 /**
5158 * A field visitor that obtains all attributes and annotations of a field that is found in the
5159 * class file but that discards all code.
5160 */
5161 protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5162
5163 /**
5164 * The field pool record to apply onto the field visitor.
5165 */
5166 private final FieldPool.Record record;
5167
5168 /**
5169 * Creates a new attribute obtaining field visitor.
5170 *
5171 * @param fieldVisitor The field visitor to delegate to.
5172 * @param record The field pool record to apply onto the field visitor.
5173 */
5174 protected AttributeObtainingFieldVisitor(FieldVisitor fieldVisitor, FieldPool.Record record) {
5175 super(OpenedClassReader.ASM_API, fieldVisitor);
5176 this.record = record;
5177 }
5178
5179 @Override
5180 public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5181 return annotationRetention.isEnabled()
5182 ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
5183 : IGNORE_ANNOTATION;
5184 }
5185
5186 @Override
5187 public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5188 return annotationRetention.isEnabled()
5189 ? super.visitAnnotation(descriptor, visible)
5190 : IGNORE_ANNOTATION;
5191 }
5192
5193 @Override
5194 public void visitEnd() {
5195 record.apply(fv, annotationValueFilterFactory);
5196 super.visitEnd();
5197 }
5198 }
5199
5200 /**
5201 * A record component visitor that obtains all attributes and annotations of a record component that is found
5202 * in the class file but discards all code.
5203 */
5204 protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5205
5206 /**
5207 * The record component pool record to apply onto the record component visitor.
5208 */
5209 private final RecordComponentPool.Record record;
5210
5211 /**
5212 * Creates a new attribute obtaining record component visitor.
5213 *
5214 * @param recordComponentVisitor The record component visitor to delegate to.
5215 * @param record The record component pool record to apply onto the record component visitor.
5216 */
5217 protected AttributeObtainingRecordComponentVisitor(RecordComponentVisitor recordComponentVisitor, RecordComponentPool.Record record) {
5218 super(OpenedClassReader.ASM_API, recordComponentVisitor);
5219 this.record = record;
5220 }
5221
5222 @Override
5223 public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5224 return annotationRetention.isEnabled()
5225 ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
5226 : IGNORE_ANNOTATION;
5227 }
5228
5229 @Override
5230 public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5231 return annotationRetention.isEnabled()
5232 ? super.visitAnnotation(descriptor, visible)
5233 : IGNORE_ANNOTATION;
5234 }
5235
5236 @Override
5237 public void visitEnd() {
5238 record.apply(getDelegate(), annotationValueFilterFactory);
5239 super.visitEnd();
5240 }
5241 }
5242
5243 /**
5244 * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5245 * method while copying all attributes and annotations to the actual method.
5246 */
5247 protected class CodePreservingMethodVisitor extends MethodVisitor {
5248
5249 /**
5250 * The method visitor of the actual method.
5251 */
5252 private final MethodVisitor actualMethodVisitor;
5253
5254 /**
5255 * The method pool entry to apply.
5256 */
5257 private final MethodPool.Record record;
5258
5259 /**
5260 * The resolution of a potential rebased method.
5261 */
5262 private final MethodRebaseResolver.Resolution resolution;
5263
5264 /**
5265 * Creates a new code preserving method visitor.
5266 *
5267 * @param actualMethodVisitor The method visitor of the actual method.
5268 * @param record The method pool entry to apply.
5269 * @param resolution The resolution of the method rebase resolver in use.
5270 */
5271 protected CodePreservingMethodVisitor(MethodVisitor actualMethodVisitor,
5272 MethodPool.Record record,
5273 MethodRebaseResolver.Resolution resolution) {
5274 super(OpenedClassReader.ASM_API, actualMethodVisitor);
5275 this.actualMethodVisitor = actualMethodVisitor;
5276 this.record = record;
5277 this.resolution = resolution;
5278 record.applyHead(actualMethodVisitor);
5279 }
5280
5281 @Override
5282 public AnnotationVisitor visitAnnotationDefault() {
5283 return IGNORE_ANNOTATION; // Annotation types can never be rebased.
5284 }
5285
5286 @Override
5287 public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5288 return annotationRetention.isEnabled()
5289 ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
5290 : IGNORE_ANNOTATION;
5291 }
5292
5293 @Override
5294 public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5295 return annotationRetention.isEnabled()
5296 ? super.visitAnnotation(descriptor, visible)
5297 : IGNORE_ANNOTATION;
5298 }
5299
5300 @Override
5301 public void visitAnnotableParameterCount(int count, boolean visible) {
5302 if (annotationRetention.isEnabled()) {
5303 super.visitAnnotableParameterCount(count, visible);
5304 }
5305 }
5306
5307 @Override
5308 public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5309 return annotationRetention.isEnabled()
5310 ? super.visitParameterAnnotation(index, descriptor, visible)
5311 : IGNORE_ANNOTATION;
5312 }
5313
5314 @Override
5315 public void visitCode() {
5316 record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
5317 actualMethodVisitor.visitEnd();
5318 mv = resolution.isRebased()
5319 ? cv.visitMethod(resolution.getResolvedMethod().getActualModifiers(),
5320 resolution.getResolvedMethod().getInternalName(),
5321 resolution.getResolvedMethod().getDescriptor(),
5322 resolution.getResolvedMethod().getGenericSignature(),
5323 resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames())
5324 : IGNORE_METHOD;
5325 super.visitCode();
5326 }
5327
5328 @Override
5329 public void visitMaxs(int stackSize, int localVariableLength) {
5330 super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
5331 }
5332 }
5333
5334 /**
5335 * A method visitor that obtains all attributes and annotations of a method that is found in the
5336 * class file but that discards all code.
5337 */
5338 protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5339
5340 /**
5341 * The method visitor to which the actual method is to be written to.
5342 */
5343 private final MethodVisitor actualMethodVisitor;
5344
5345 /**
5346 * The method pool entry to apply.
5347 */
5348 private final MethodPool.Record record;
5349
5350 /**
5351 * Creates a new attribute obtaining method visitor.
5352 *
5353 * @param actualMethodVisitor The method visitor of the actual method.
5354 * @param record The method pool entry to apply.
5355 */
5356 protected AttributeObtainingMethodVisitor(MethodVisitor actualMethodVisitor, MethodPool.Record record) {
5357 super(OpenedClassReader.ASM_API, actualMethodVisitor);
5358 this.actualMethodVisitor = actualMethodVisitor;
5359 this.record = record;
5360 record.applyHead(actualMethodVisitor);
5361 }
5362
5363 @Override
5364 public AnnotationVisitor visitAnnotationDefault() {
5365 return IGNORE_ANNOTATION;
5366 }
5367
5368 @Override
5369 public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5370 return annotationRetention.isEnabled()
5371 ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
5372 : IGNORE_ANNOTATION;
5373 }
5374
5375 @Override
5376 public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5377 return annotationRetention.isEnabled()
5378 ? super.visitAnnotation(descriptor, visible)
5379 : IGNORE_ANNOTATION;
5380 }
5381
5382 @Override
5383 public void visitAnnotableParameterCount(int count, boolean visible) {
5384 if (annotationRetention.isEnabled()) {
5385 super.visitAnnotableParameterCount(count, visible);
5386 }
5387 }
5388
5389 @Override
5390 public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5391 return annotationRetention.isEnabled()
5392 ? super.visitParameterAnnotation(index, descriptor, visible)
5393 : IGNORE_ANNOTATION;
5394 }
5395
5396 @Override
5397 public void visitCode() {
5398 mv = IGNORE_METHOD;
5399 }
5400
5401 @Override
5402 public void visitEnd() {
5403 record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
5404 actualMethodVisitor.visitEnd();
5405 }
5406 }
5407 }
5408 }
5409
5410 /**
5411 * A default type writer that only applies a type decoration.
5412 *
5413 * @param <V> The best known loaded type for the dynamically created type.
5414 */
5415 protected static class WithDecorationOnly<V> extends ForInlining<V> {
5416
5417 /**
5418 * Creates a new inlining type writer that only applies a decoration.
5419 *
5420 * @param instrumentedType The instrumented type to be created.
5421 * @param classFileVersion The class file specified by the user.
5422 * @param auxiliaryTypes The explicit auxiliary types to add to the created type.
5423 * @param methods The instrumented type's declared and virtually inherited methods.
5424 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
5425 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
5426 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5427 * @param annotationRetention The annotation retention to apply.
5428 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
5429 * @param implementationContextFactory The implementation context factory to apply.
5430 * @param typeValidation Determines if a type should be explicitly validated.
5431 * @param classWriterStrategy The class writer strategy to use.
5432 * @param typePool The type pool to use for computing stack map frames, if required.
5433 * @param classFileLocator The class file locator for locating the original type's class file.
5434 */
5435 protected WithDecorationOnly(TypeDescription instrumentedType,
5436 ClassFileVersion classFileVersion,
5437 List<? extends DynamicType> auxiliaryTypes,
5438 MethodList<?> methods,
5439 TypeAttributeAppender typeAttributeAppender,
5440 AsmVisitorWrapper asmVisitorWrapper,
5441 AnnotationValueFilter.Factory annotationValueFilterFactory,
5442 AnnotationRetention annotationRetention,
5443 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5444 Implementation.Context.Factory implementationContextFactory,
5445 TypeValidation typeValidation,
5446 ClassWriterStrategy classWriterStrategy,
5447 TypePool typePool,
5448 ClassFileLocator classFileLocator) {
5449 super(instrumentedType,
5450 classFileVersion,
5451 FieldPool.Disabled.INSTANCE,
5452 RecordComponentPool.Disabled.INSTANCE,
5453 auxiliaryTypes,
5454 new LazyFieldList(instrumentedType),
5455 methods,
5456 new MethodList.Empty<MethodDescription>(),
5457 new RecordComponentList.Empty<RecordComponentDescription.InDefinedShape>(), // TODO
5458 LoadedTypeInitializer.NoOp.INSTANCE,
5459 TypeInitializer.None.INSTANCE,
5460 typeAttributeAppender,
5461 asmVisitorWrapper,
5462 annotationValueFilterFactory,
5463 annotationRetention,
5464 auxiliaryTypeNamingStrategy,
5465 implementationContextFactory,
5466 typeValidation,
5467 classWriterStrategy,
5468 typePool,
5469 instrumentedType,
5470 classFileLocator);
5471 }
5472
5473 /**
5474 * {@inheritDoc}
5475 */
5476 protected ClassVisitor writeTo(ClassVisitor classVisitor,
5477 TypeInitializer typeInitializer,
5478 ContextRegistry contextRegistry,
5479 int writerFlags,
5480 int readerFlags) {
5481 if (typeInitializer.isDefined()) {
5482 throw new UnsupportedOperationException("Cannot apply a type initializer for a decoration");
5483 }
5484 return new DecorationClassVisitor(classVisitor, contextRegistry, writerFlags, readerFlags);
5485 }
5486
5487 /**
5488 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5489 */
5490 protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5491
5492 /**
5493 * The instrumented type.
5494 */
5495 private final TypeDescription instrumentedType;
5496
5497 /**
5498 * Creates a lazy field list.
5499 *
5500 * @param instrumentedType The instrumented type.
5501 */
5502 protected LazyFieldList(TypeDescription instrumentedType) {
5503 this.instrumentedType = instrumentedType;
5504 }
5505
5506 /**
5507 * {@inheritDoc}
5508 */
5509 public FieldDescription.InDefinedShape get(int index) {
5510 return instrumentedType.getDeclaredFields().get(index);
5511 }
5512
5513 /**
5514 * {@inheritDoc}
5515 */
5516 public int size() {
5517 return instrumentedType.getDeclaredFields().size();
5518 }
5519 }
5520
5521 /**
5522 * A class visitor that decorates an existing type.
5523 */
5524 @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM")
5525 protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
5526
5527 /**
5528 * A context registry to register the lazily created implementation context to.
5529 */
5530 private final ContextRegistry contextRegistry;
5531
5532 /**
5533 * The writer flags being used.
5534 */
5535 private final int writerFlags;
5536
5537 /**
5538 * The reader flags being used.
5539 */
5540 private final int readerFlags;
5541
5542 /**
5543 * The implementation context to use or {@code null} if the context is not yet initialized.
5544 */
5545 private Implementation.Context.ExtractableView implementationContext;
5546
5547 /**
5548 * Creates a class visitor which is capable of decorating an existent class on the fly.
5549 *
5550 * @param classVisitor The underlying class visitor to which writes are delegated.
5551 * @param contextRegistry A context registry to register the lazily created implementation context to.
5552 * @param writerFlags The writer flags being used.
5553 * @param readerFlags The reader flags being used.
5554 */
5555 protected DecorationClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
5556 super(OpenedClassReader.ASM_API, classVisitor);
5557 this.contextRegistry = contextRegistry;
5558 this.writerFlags = writerFlags;
5559 this.readerFlags = readerFlags;
5560 }
5561
5562 @Override
5563 public void visit(int classFileVersionNumber,
5564 int modifiers,
5565 String internalName,
5566 String genericSignature,
5567 String superClassInternalName,
5568 String[] interfaceTypeInternalName) {
5569 ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
5570 implementationContext = implementationContextFactory.make(instrumentedType,
5571 auxiliaryTypeNamingStrategy,
5572 typeInitializer,
5573 classFileVersion,
5574 WithDecorationOnly.this.classFileVersion);
5575 contextRegistry.setImplementationContext(implementationContext);
5576 cv = asmVisitorWrapper.wrap(instrumentedType,
5577 cv,
5578 implementationContext,
5579 typePool,
5580 fields,
5581 methods,
5582 writerFlags,
5583 readerFlags);
5584 cv.visit(classFileVersionNumber, modifiers, internalName, genericSignature, superClassInternalName, interfaceTypeInternalName);
5585 }
5586
5587 @Override
5588 protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5589 return annotationRetention.isEnabled()
5590 ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
5591 : IGNORE_ANNOTATION;
5592 }
5593
5594 @Override
5595 protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5596 return annotationRetention.isEnabled()
5597 ? cv.visitAnnotation(descriptor, visible)
5598 : IGNORE_ANNOTATION;
5599 }
5600
5601 @Override
5602 protected void onAfterAttributes() {
5603 typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
5604 }
5605
5606 @Override
5607 protected void onVisitEnd() {
5608 implementationContext.drain(this, cv, annotationValueFilterFactory);
5609 cv.visitEnd();
5610 }
5611
5612 /**
5613 * {@inheritDoc}
5614 */
5615 public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
5616 /* do nothing */
5617 }
5618 }
5619 }
5620 }
5621
5622 /**
5623 * A type writer that creates a class file that is not based upon another, existing class.
5624 *
5625 * @param <U> The best known loaded type for the dynamically created type.
5626 */
5627 @HashCodeAndEqualsPlugin.Enhance
5628 public static class ForCreation<U> extends Default<U> {
5629
5630 /**
5631 * The method pool to use.
5632 */
5633 private final MethodPool methodPool;
5634
5635 /**
5636 * Creates a new default type writer for creating a new type that is not based on an existing class file.
5637 *
5638 * @param instrumentedType The instrumented type to be created.
5639 * @param classFileVersion The class file version to write the instrumented type in and to apply when creating auxiliary types.
5640 * @param fieldPool The field pool to use.
5641 * @param methodPool The method pool to use.
5642 * @param recordComponentPool The record component pool to use.
5643 * @param auxiliaryTypes A list of auxiliary types to add to the created type.
5644 * @param fields The instrumented type's declared fields.
5645 * @param methods The instrumented type's declared and virtually inherited methods.
5646 * @param instrumentedMethods The instrumented methods relevant to this type creation.
5647 * @param recordComponents The instrumented type's record components.
5648 * @param loadedTypeInitializer The loaded type initializer to apply onto the created type after loading.
5649 * @param typeInitializer The type initializer to include in the created type's type initializer.
5650 * @param typeAttributeAppender The type attribute appender to apply onto the instrumented type.
5651 * @param asmVisitorWrapper The ASM visitor wrapper to apply onto the class writer.
5652 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5653 * @param annotationRetention The annotation retention to apply.
5654 * @param auxiliaryTypeNamingStrategy The naming strategy for auxiliary types to apply.
5655 * @param implementationContextFactory The implementation context factory to apply.
5656 * @param typeValidation Determines if a type should be explicitly validated.
5657 * @param classWriterStrategy The class writer strategy to use.
5658 * @param typePool The type pool to use for computing stack map frames, if required.
5659 */
5660 protected ForCreation(TypeDescription instrumentedType,
5661 ClassFileVersion classFileVersion,
5662 FieldPool fieldPool,
5663 MethodPool methodPool,
5664 RecordComponentPool recordComponentPool,
5665 List<? extends DynamicType> auxiliaryTypes,
5666 FieldList<FieldDescription.InDefinedShape> fields,
5667 MethodList<?> methods,
5668 MethodList<?> instrumentedMethods,
5669 RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
5670 LoadedTypeInitializer loadedTypeInitializer,
5671 TypeInitializer typeInitializer,
5672 TypeAttributeAppender typeAttributeAppender,
5673 AsmVisitorWrapper asmVisitorWrapper,
5674 AnnotationValueFilter.Factory annotationValueFilterFactory,
5675 AnnotationRetention annotationRetention,
5676 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5677 Implementation.Context.Factory implementationContextFactory,
5678 TypeValidation typeValidation,
5679 ClassWriterStrategy classWriterStrategy,
5680 TypePool typePool) {
5681 super(instrumentedType,
5682 classFileVersion,
5683 fieldPool,
5684 recordComponentPool,
5685 auxiliaryTypes,
5686 fields,
5687 methods,
5688 instrumentedMethods,
5689 recordComponents,
5690 loadedTypeInitializer,
5691 typeInitializer,
5692 typeAttributeAppender,
5693 asmVisitorWrapper,
5694 annotationValueFilterFactory,
5695 annotationRetention,
5696 auxiliaryTypeNamingStrategy,
5697 implementationContextFactory,
5698 typeValidation,
5699 classWriterStrategy,
5700 typePool);
5701 this.methodPool = methodPool;
5702 }
5703
5704 @Override
5705 protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
5706 int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS);
5707 ClassWriter classWriter = classWriterStrategy.resolve(writerFlags, typePool);
5708 Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
5709 auxiliaryTypeNamingStrategy,
5710 typeInitializer,
5711 classFileVersion,
5712 classFileVersion);
5713 ClassVisitor classVisitor = asmVisitorWrapper.wrap(instrumentedType,
5714 ValidatingClassVisitor.of(classWriter, typeValidation),
5715 implementationContext,
5716 typePool,
5717 fields,
5718 methods,
5719 writerFlags,
5720 asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS));
5721 classVisitor.visit(classFileVersion.getMinorMajorVersion(),
5722 instrumentedType.getActualModifiers(!instrumentedType.isInterface()),
5723 instrumentedType.getInternalName(),
5724 instrumentedType.getGenericSignature(),
5725 (instrumentedType.getSuperClass() == null
5726 ? TypeDescription.OBJECT
5727 : instrumentedType.getSuperClass().asErasure()).getInternalName(),
5728 instrumentedType.getInterfaces().asErasures().toInternalNames());
5729 if (!instrumentedType.isNestHost()) {
5730 classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
5731 }
5732 for (TypeDescription typeDescription : instrumentedType.getPermittedSubclasses()) {
5733 classVisitor.visitPermittedSubclass(typeDescription.getInternalName());
5734 }
5735 MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
5736 if (enclosingMethod != null) {
5737 classVisitor.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
5738 enclosingMethod.getInternalName(),
5739 enclosingMethod.getDescriptor());
5740 } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
5741 classVisitor.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
5742 }
5743 typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
5744 for (RecordComponentDescription recordComponentDescription : recordComponents) {
5745 recordComponentPool.target(recordComponentDescription).apply(classVisitor, annotationValueFilterFactory);
5746 }
5747 for (FieldDescription fieldDescription : fields) {
5748 fieldPool.target(fieldDescription).apply(classVisitor, annotationValueFilterFactory);
5749 }
5750 for (MethodDescription methodDescription : instrumentedMethods) {
5751 methodPool.target(methodDescription).apply(classVisitor, implementationContext, annotationValueFilterFactory);
5752 }
5753 implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
5754 methodPool,
5755 annotationValueFilterFactory), classVisitor, annotationValueFilterFactory);
5756 if (instrumentedType.isNestHost()) {
5757 for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
5758 classVisitor.visitNestMember(typeDescription.getInternalName());
5759 }
5760 }
5761 TypeDescription declaringType = instrumentedType.getDeclaringType();
5762 if (declaringType != null) {
5763 classVisitor.visitInnerClass(instrumentedType.getInternalName(),
5764 declaringType.getInternalName(),
5765 instrumentedType.getSimpleName(),
5766 instrumentedType.getModifiers());
5767 } else if (instrumentedType.isLocalType()) {
5768 classVisitor.visitInnerClass(instrumentedType.getInternalName(),
5769 NO_REFERENCE,
5770 instrumentedType.getSimpleName(),
5771 instrumentedType.getModifiers());
5772 } else if (instrumentedType.isAnonymousType()) {
5773 classVisitor.visitInnerClass(instrumentedType.getInternalName(),
5774 NO_REFERENCE,
5775 NO_REFERENCE,
5776 instrumentedType.getModifiers());
5777 }
5778 for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
5779 classVisitor.visitInnerClass(typeDescription.getInternalName(),
5780 typeDescription.isMemberType()
5781 ? instrumentedType.getInternalName()
5782 : NO_REFERENCE,
5783 typeDescription.isAnonymousType()
5784 ? NO_REFERENCE
5785 : typeDescription.getSimpleName(),
5786 typeDescription.getModifiers());
5787 }
5788 classVisitor.visitEnd();
5789 return new UnresolvedType(classWriter.toByteArray(), implementationContext.getAuxiliaryTypes());
5790 }
5791 }
5792
5793 /**
5794 * An action to write a class file to the dumping location.
5795 */
5796 @HashCodeAndEqualsPlugin.Enhance
5797 protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
5798
5799 /**
5800 * Indicates that nothing is returned from this action.
5801 */
5802 private static final Void NOTHING = null;
5803
5804 /**
5805 * The target folder for writing the class file to.
5806 */
5807 private final String target;
5808
5809 /**
5810 * The instrumented type.
5811 */
5812 private final TypeDescription instrumentedType;
5813
5814 /**
5815 * {@code true} if the dumped class file is an input to a class transformation.
5816 */
5817 private final boolean original;
5818
5819 /**
5820 * The suffix to append to the dumped class file.
5821 */
5822 private final long suffix;
5823
5824 /**
5825 * The type's binary representation.
5826 */
5827 private final byte[] binaryRepresentation;
5828
5829 /**
5830 * Creates a new class dump action.
5831 *
5832 * @param target The target folder for writing the class file to.
5833 * @param instrumentedType The instrumented type.
5834 * @param original {@code true} if the dumped class file is an input to a class transformation.
5835 * @param suffix The suffix to append to the dumped class file.
5836 * @param binaryRepresentation The type's binary representation.
5837 */
5838 protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
5839 this.target = target;
5840 this.instrumentedType = instrumentedType;
5841 this.original = original;
5842 this.suffix = suffix;
5843 this.binaryRepresentation = binaryRepresentation;
5844 }
5845
5846 /**
5847 * {@inheritDoc}
5848 */
5849 public Void run() throws Exception {
5850 OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
5851 + (original ? "-original." : ".")
5852 + suffix
5853 + ".class"));
5854 try {
5855 outputStream.write(binaryRepresentation);
5856 return NOTHING;
5857 } finally {
5858 outputStream.close();
5859 }
5860 }
5861
5862 /**
5863 * A dispatcher for dumping class files to the file system.
5864 */
5865 protected interface Dispatcher {
5866
5867 /**
5868 * Dumps a class file to the file system.
5869 *
5870 * @param instrumentedType The type to dump.
5871 * @param original {@code true} if the class file is in its original state.
5872 * @param binaryRepresentation The class file's binary representation.
5873 */
5874 void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
5875
5876 /**
5877 * A disabled dispatcher that does not dump any class files.
5878 */
5879 enum Disabled implements Dispatcher {
5880
5881 /**
5882 * The singleton instance.
5883 */
5884 INSTANCE;
5885
5886 /**
5887 * {@inheritDoc}
5888 */
5889 public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
5890 /* do nothing */
5891 }
5892 }
5893
5894 /**
5895 * An enabled dispatcher that dumps class files to a given folder.
5896 */
5897 @HashCodeAndEqualsPlugin.Enhance
5898 class Enabled implements Dispatcher {
5899
5900 /**
5901 * The folder to write class files to.
5902 */
5903 private final String folder;
5904
5905 /**
5906 * The timestamp to append.
5907 */
5908 private final long timestamp;
5909
5910 /**
5911 * Creates a new dispatcher for dumping class files.
5912 *
5913 * @param folder The folder to write class files to.
5914 * @param timestamp The timestamp to append.
5915 */
5916 protected Enabled(String folder, long timestamp) {
5917 this.folder = folder;
5918 this.timestamp = timestamp;
5919 }
5920
5921 /**
5922 * {@inheritDoc}
5923 */
5924 public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
5925 try {
5926 AccessController.doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
5927 } catch (Exception exception) {
5928 exception.printStackTrace();
5929 }
5930 }
5931 }
5932 }
5933 }
5934 }
5935 }
5936