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 trueif 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 nullif no default value is defined.
137              * @return The default value for the represented field or {@code nullif 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(falsefalse),
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(truefalse),
447
448                 /**
449                  * Describes a method that is implemented in byte code.
450                  */

451                 IMPLEMENTED(truetrue);
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 trueif 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 trueif 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 trueif 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 nullif 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 trueif this type implements at least one interface.
2454                  * @param isGeneric         {@code trueif 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 trueif this field is public.
2463                  * @param isStatic  {@code trueif this field is static.
2464                  * @param isFinal   {@code trueif this field is final.
2465                  * @param isGeneric {@code trueif 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 trueif the method is abstract.
2474                  * @param isPublic                   {@code trueif this method is public.
2475                  * @param isPrivate                  {@code trueif this method is private.
2476                  * @param isStatic                   {@code trueif this method is static.
2477                  * @param isVirtual                  {@code trueif this method is virtual.
2478                  * @param isConstructor              {@code trueif this method is a constructor.
2479                  * @param isDefaultValueIncompatible {@code trueif a method's signature cannot describe an annotation property method.
2480                  * @param isGeneric                  {@code trueif 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 trueif 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 trueif 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 trueif 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 trueif 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 publicstaticfinal 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 trueif 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 trueif 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 publicstaticfinal 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 nullif 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 trueif the visitor is required to add frames.
4161                          * @param expandFrames                 {@code trueif 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 trueif 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 trueif frames must be computed.
4191                          * @param expandFrames                 {@code trueif 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 trueif frames must be computed.
4214                          * @param expandFrames                 {@code trueif 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 trueif frames must be computed.
4237                          * @param expandFrames                 {@code trueif 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 trueif the visitor is required to add frames.
4443                              * @param expandFrames                 {@code trueif 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, falsefalse);
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 trueif the visitor is required to add frames.
4510                                  * @param expandFrames                 {@code trueif 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 trueif the visitor is required to add frames.
4567                              * @param expandFrames                 {@code trueif 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 trueif the visitor is required to add frames.
4619                                  * @param expandFrames                 {@code trueif 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 trueif the visitor is required to add frames.
4654                                  * @param expandFrames                 {@code trueif 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 nullif the pool was not yet initialized.
4746                      */

4747                     private MethodPool methodPool;
4748
4749                     /**
4750                      * The initialization handler to use or {@code nullif the handler was not yet initialized.
4751                      */

4752                     private InitializationHandler initializationHandler;
4753
4754                     /**
4755                      * The implementation context for this class creation or {@code nullif it was not yet created.
4756                      */

4757                     private Implementation.Context.ExtractableView implementationContext;
4758
4759                     /**
4760                      * {@code trueif 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 trueif 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 nullif 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 trueif 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 trueif 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 trueif 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