• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

raphw / byte-buddy / #801

27 Oct 2025 09:37AM UTC coverage: 84.715% (-0.4%) from 85.118%
#801

push

raphw
Fix imports.

29586 of 34924 relevant lines covered (84.72%)

0.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

81.09
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java
1
/*
2
 * Copyright 2014 - Present 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.AccessControllerPlugin;
22
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
23
import net.bytebuddy.description.annotation.AnnotationList;
24
import net.bytebuddy.description.annotation.AnnotationValue;
25
import net.bytebuddy.description.field.FieldDescription;
26
import net.bytebuddy.description.field.FieldList;
27
import net.bytebuddy.description.method.MethodDescription;
28
import net.bytebuddy.description.method.MethodList;
29
import net.bytebuddy.description.method.ParameterDescription;
30
import net.bytebuddy.description.method.ParameterList;
31
import net.bytebuddy.description.modifier.ModifierContributor;
32
import net.bytebuddy.description.modifier.Visibility;
33
import net.bytebuddy.description.type.PackageDescription;
34
import net.bytebuddy.description.type.RecordComponentDescription;
35
import net.bytebuddy.description.type.RecordComponentList;
36
import net.bytebuddy.description.type.TypeDefinition;
37
import net.bytebuddy.description.type.TypeDescription;
38
import net.bytebuddy.description.type.TypeList;
39
import net.bytebuddy.dynamic.ClassFileLocator;
40
import net.bytebuddy.dynamic.DynamicType;
41
import net.bytebuddy.dynamic.TypeResolutionStrategy;
42
import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
43
import net.bytebuddy.dynamic.scaffold.inline.RebaseImplementationTarget;
44
import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget;
45
import net.bytebuddy.implementation.Implementation;
46
import net.bytebuddy.implementation.LoadedTypeInitializer;
47
import net.bytebuddy.implementation.attribute.AnnotationAppender;
48
import net.bytebuddy.implementation.attribute.AnnotationRetention;
49
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
50
import net.bytebuddy.implementation.attribute.FieldAttributeAppender;
51
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
52
import net.bytebuddy.implementation.attribute.RecordComponentAttributeAppender;
53
import net.bytebuddy.implementation.attribute.TypeAttributeAppender;
54
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
55
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
56
import net.bytebuddy.implementation.bytecode.StackManipulation;
57
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
58
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
59
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
60
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
61
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
62
import net.bytebuddy.pool.TypePool;
63
import net.bytebuddy.utility.AsmClassReader;
64
import net.bytebuddy.utility.AsmClassWriter;
65
import net.bytebuddy.utility.CompoundList;
66
import net.bytebuddy.utility.OpenedClassReader;
67
import net.bytebuddy.utility.nullability.AlwaysNull;
68
import net.bytebuddy.utility.nullability.MaybeNull;
69
import net.bytebuddy.utility.nullability.UnknownNull;
70
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
71
import net.bytebuddy.utility.visitor.ContextClassVisitor;
72
import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
73
import org.objectweb.asm.AnnotationVisitor;
74
import org.objectweb.asm.ClassReader;
75
import org.objectweb.asm.ClassVisitor;
76
import org.objectweb.asm.ClassWriter;
77
import org.objectweb.asm.ConstantDynamic;
78
import org.objectweb.asm.FieldVisitor;
79
import org.objectweb.asm.Handle;
80
import org.objectweb.asm.Label;
81
import org.objectweb.asm.MethodVisitor;
82
import org.objectweb.asm.Opcodes;
83
import org.objectweb.asm.RecordComponentVisitor;
84
import org.objectweb.asm.Type;
85
import org.objectweb.asm.TypePath;
86
import org.objectweb.asm.commons.ClassRemapper;
87
import org.objectweb.asm.commons.Remapper;
88
import org.objectweb.asm.commons.SimpleRemapper;
89

90
import javax.annotation.Nonnull;
91
import java.io.File;
92
import java.io.FileOutputStream;
93
import java.io.IOException;
94
import java.io.OutputStream;
95
import java.security.PrivilegedAction;
96
import java.security.PrivilegedExceptionAction;
97
import java.util.ArrayList;
98
import java.util.Collections;
99
import java.util.HashSet;
100
import java.util.LinkedHashMap;
101
import java.util.LinkedHashSet;
102
import java.util.List;
103
import java.util.Set;
104

105
import static net.bytebuddy.matcher.ElementMatchers.is;
106
import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf;
107
import static net.bytebuddy.matcher.ElementMatchers.not;
108

109
/**
110
 * A type writer is a utility for writing an actual class file using the ASM library.
111
 *
112
 * @param <T> The best known loaded type for the dynamically created type.
113
 */
114
public interface TypeWriter<T> {
115

116
    /**
117
     * A system property that indicates a folder for Byte Buddy to dump class files of all types that it creates.
118
     * If this property is not set, Byte Buddy does not dump any class files. This property is only read a single
119
     * time which is why it must be set on application start-up.
120
     */
121
    String DUMP_PROPERTY = "net.bytebuddy.dump";
122

123
    /**
124
     * Creates the dynamic type that is described by this type writer.
125
     *
126
     * @param typeResolver The type resolution strategy to use.
127
     * @return An unloaded dynamic type that describes the created type.
128
     */
129
    DynamicType.Unloaded<T> make(TypeResolutionStrategy.Resolved typeResolver);
130

131
    /**
132
     * Wraps another ASM class visitor with a visitor that represents this ASM class writer.
133
     *
134
     * @param classVisitor The class visitor to wrap.
135
     * @param writerFlags  The ASM writer flags to consider.
136
     * @param readerFlags  The ASM reader flags to consider.
137
     * @return The supplied class visitor wrapped by this type writer.
138
     */
139
    ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags);
140

141
    /**
142
     * An field pool that allows a lookup for how to implement a field.
143
     */
144
    interface FieldPool {
145

146
        /**
147
         * Looks up a handler entry for a given field.
148
         *
149
         * @param fieldDescription The field being processed.
150
         * @return A handler entry for the given field.
151
         */
152
        Record target(FieldDescription fieldDescription);
153

154
        /**
155
         * An entry of a field pool that describes how a field is implemented.
156
         *
157
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.FieldPool
158
         */
159
        interface Record {
160

161
            /**
162
             * Determines if this record is implicit, i.e is not defined by a {@link FieldPool}.
163
             *
164
             * @return {@code true} if this record is implicit.
165
             */
166
            boolean isImplicit();
167

168
            /**
169
             * Returns the field that this record represents.
170
             *
171
             * @return The field that this record represents.
172
             */
173
            FieldDescription getField();
174

175
            /**
176
             * Returns the field attribute appender for a given field.
177
             *
178
             * @return The attribute appender to be applied on the given field.
179
             */
180
            FieldAttributeAppender getFieldAppender();
181

182
            /**
183
             * Resolves the default value that this record represents. This is not possible for implicit records.
184
             *
185
             * @param defaultValue The default value that was defined previously or {@code null} if no default value is defined.
186
             * @return The default value for the represented field or {@code null} if no default value is to be defined.
187
             */
188
            @MaybeNull
189
            Object resolveDefault(@MaybeNull Object defaultValue);
190

191
            /**
192
             * Writes this entry to a given class visitor.
193
             *
194
             * @param classVisitor                 The class visitor to which this entry is to be written to.
195
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
196
             */
197
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
198

199
            /**
200
             * Applies this record to a field visitor. This is not possible for implicit records.
201
             *
202
             * @param fieldVisitor                 The field visitor onto which this record is to be applied.
203
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
204
             */
205
            void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
206

207
            /**
208
             * A record for a simple field without a default value where all of the field's declared annotations are appended.
209
             */
210
            @HashCodeAndEqualsPlugin.Enhance
211
            class ForImplicitField implements Record {
212

213
                /**
214
                 * The implemented field.
215
                 */
216
                private final FieldDescription fieldDescription;
217

218
                /**
219
                 * Creates a new record for a simple field.
220
                 *
221
                 * @param fieldDescription The described field.
222
                 */
223
                public ForImplicitField(FieldDescription fieldDescription) {
1✔
224
                    this.fieldDescription = fieldDescription;
1✔
225
                }
1✔
226

227
                /**
228
                 * {@inheritDoc}
229
                 */
230
                public boolean isImplicit() {
231
                    return true;
1✔
232
                }
233

234
                /**
235
                 * {@inheritDoc}
236
                 */
237
                public FieldDescription getField() {
238
                    return fieldDescription;
1✔
239
                }
240

241
                /**
242
                 * {@inheritDoc}
243
                 */
244
                public FieldAttributeAppender getFieldAppender() {
245
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
1✔
246
                }
247

248
                /**
249
                 * {@inheritDoc}
250
                 */
251
                public Object resolveDefault(@MaybeNull Object defaultValue) {
252
                    throw new IllegalStateException("An implicit field record does not expose a default value: " + this);
1✔
253
                }
254

255
                /**
256
                 * {@inheritDoc}
257
                 */
258
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
259
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
260
                            fieldDescription.getInternalName(),
1✔
261
                            fieldDescription.getDescriptor(),
1✔
262
                            fieldDescription.getGenericSignature(),
1✔
263
                            FieldDescription.NO_DEFAULT_VALUE);
264
                    if (fieldVisitor != null) {
1✔
265
                        FieldAttributeAppender.ForInstrumentedField.INSTANCE.apply(fieldVisitor,
1✔
266
                                fieldDescription,
267
                                annotationValueFilterFactory.on(fieldDescription));
1✔
268
                        fieldVisitor.visitEnd();
1✔
269
                    }
270
                }
1✔
271

272
                /**
273
                 * {@inheritDoc}
274
                 */
275
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
276
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
277
                }
278
            }
279

280
            /**
281
             * A record for a rich field with attributes and a potential default value.
282
             */
283
            @HashCodeAndEqualsPlugin.Enhance
284
            class ForExplicitField implements Record {
285

286
                /**
287
                 * The attribute appender for the field.
288
                 */
289
                private final FieldAttributeAppender attributeAppender;
290

291
                /**
292
                 * The field's default value.
293
                 */
294
                @MaybeNull
295
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
296
                private final Object defaultValue;
297

298
                /**
299
                 * The implemented field.
300
                 */
301
                private final FieldDescription fieldDescription;
302

303
                /**
304
                 * Creates a record for a rich field.
305
                 *
306
                 * @param attributeAppender The attribute appender for the field.
307
                 * @param defaultValue      The field's default value.
308
                 * @param fieldDescription  The implemented field.
309
                 */
310
                public ForExplicitField(FieldAttributeAppender attributeAppender,
311
                                        @MaybeNull Object defaultValue,
312
                                        FieldDescription fieldDescription) {
1✔
313
                    this.attributeAppender = attributeAppender;
1✔
314
                    this.defaultValue = defaultValue;
1✔
315
                    this.fieldDescription = fieldDescription;
1✔
316
                }
1✔
317

318
                /**
319
                 * {@inheritDoc}
320
                 */
321
                public boolean isImplicit() {
322
                    return false;
1✔
323
                }
324

325
                /**
326
                 * {@inheritDoc}
327
                 */
328
                public FieldDescription getField() {
329
                    return fieldDescription;
1✔
330
                }
331

332
                /**
333
                 * {@inheritDoc}
334
                 */
335
                public FieldAttributeAppender getFieldAppender() {
336
                    return attributeAppender;
1✔
337
                }
338

339
                /**
340
                 * {@inheritDoc}
341
                 */
342
                @MaybeNull
343
                public Object resolveDefault(@MaybeNull Object defaultValue) {
344
                    return this.defaultValue == null
1✔
345
                            ? defaultValue
346
                            : this.defaultValue;
347
                }
348

349
                /**
350
                 * {@inheritDoc}
351
                 */
352
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
353
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
354
                            fieldDescription.getInternalName(),
1✔
355
                            fieldDescription.getDescriptor(),
1✔
356
                            fieldDescription.getGenericSignature(),
1✔
357
                            resolveDefault(FieldDescription.NO_DEFAULT_VALUE));
1✔
358
                    if (fieldVisitor != null) {
1✔
359
                        attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
360
                        fieldVisitor.visitEnd();
1✔
361
                    }
362
                }
1✔
363

364
                /**
365
                 * {@inheritDoc}
366
                 */
367
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
368
                    attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
369
                }
1✔
370
            }
371
        }
372

373
        /**
374
         * A field pool that does not allow any look ups.
375
         */
376
        enum Disabled implements FieldPool {
1✔
377

378
            /**
379
             * The singleton instance.
380
             */
381
            INSTANCE;
1✔
382

383
            /**
384
             * {@inheritDoc}
385
             */
386
            public Record target(FieldDescription fieldDescription) {
387
                throw new IllegalStateException("Cannot look up field from disabled pool");
1✔
388
            }
389
        }
390
    }
391

392
    /**
393
     * An method pool that allows a lookup for how to implement a method.
394
     */
395
    interface MethodPool {
396

397
        /**
398
         * Looks up a handler entry for a given method.
399
         *
400
         * @param methodDescription The method being processed.
401
         * @return A handler entry for the given method.
402
         */
403
        Record target(MethodDescription methodDescription);
404

405
        /**
406
         * An entry of a method pool that describes how a method is implemented.
407
         *
408
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool
409
         */
410
        interface Record {
411

412
            /**
413
             * Returns the sort of this method instrumentation.
414
             *
415
             * @return The sort of this method instrumentation.
416
             */
417
            Sort getSort();
418

419
            /**
420
             * Returns the method that is implemented where the returned method resembles a potential transformation. An implemented
421
             * method is only defined if a method is not {@link Record.Sort#SKIPPED}.
422
             *
423
             * @return The implemented method.
424
             */
425
            MethodDescription getMethod();
426

427
            /**
428
             * The visibility to enforce for this method.
429
             *
430
             * @return The visibility to enforce for this method.
431
             */
432
            Visibility getVisibility();
433

434
            /**
435
             * Prepends the given method appender to this entry.
436
             *
437
             * @param byteCodeAppender The byte code appender to prepend.
438
             * @return This entry with the given code prepended.
439
             */
440
            Record prepend(ByteCodeAppender byteCodeAppender);
441

442
            /**
443
             * Applies this method entry. This method can always be called and might be a no-op.
444
             *
445
             * @param classVisitor                 The class visitor to which this entry should be applied.
446
             * @param implementationContext        The implementation context to which this entry should be applied.
447
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
448
             */
449
            void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
450

451
            /**
452
             * 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
453
             * {@link Record.Sort#SKIPPED}.
454
             *
455
             * @param methodVisitor The method visitor to which this entry should be applied.
456
             */
457
            void applyHead(MethodVisitor methodVisitor);
458

459
            /**
460
             * 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
461
             * entry is {@link Record.Sort#IMPLEMENTED}.
462
             *
463
             * @param methodVisitor                The method visitor to which this entry should be applied.
464
             * @param implementationContext        The implementation context to which this entry should be applied.
465
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
466
             */
467
            void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
468

469
            /**
470
             * 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
471
             * entry is {@link Record.Sort#DEFINED}.
472
             *
473
             * @param methodVisitor                The method visitor to which this entry should be applied.
474
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
475
             */
476
            void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
477

478
            /**
479
             * 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
480
             * entry is {@link Record.Sort#IMPLEMENTED}.
481
             *
482
             * @param methodVisitor         The method visitor to which this entry should be applied.
483
             * @param implementationContext The implementation context to which this entry should be applied.
484
             * @return The size requirements of the implemented code.
485
             */
486
            ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext);
487

488
            /**
489
             * The sort of an entry.
490
             */
491
            enum Sort {
1✔
492

493
                /**
494
                 * Describes a method that should not be implemented or retained in its original state.
495
                 */
496
                SKIPPED(false, false),
1✔
497

498
                /**
499
                 * Describes a method that should be defined but is abstract or native, i.e. does not define any byte code.
500
                 */
501
                DEFINED(true, false),
1✔
502

503
                /**
504
                 * Describes a method that is implemented in byte code.
505
                 */
506
                IMPLEMENTED(true, true);
1✔
507

508
                /**
509
                 * Indicates if this sort defines a method, with or without byte code.
510
                 */
511
                private final boolean define;
512

513
                /**
514
                 * Indicates if this sort defines byte code.
515
                 */
516
                private final boolean implement;
517

518
                /**
519
                 * Creates a new sort.
520
                 *
521
                 * @param define    Indicates if this sort defines a method, with or without byte code.
522
                 * @param implement Indicates if this sort defines byte code.
523
                 */
524
                Sort(boolean define, boolean implement) {
1✔
525
                    this.define = define;
1✔
526
                    this.implement = implement;
1✔
527
                }
1✔
528

529
                /**
530
                 * Indicates if this sort defines a method, with or without byte code.
531
                 *
532
                 * @return {@code true} if this sort defines a method, with or without byte code.
533
                 */
534
                public boolean isDefined() {
535
                    return define;
1✔
536
                }
537

538
                /**
539
                 * Indicates if this sort defines byte code.
540
                 *
541
                 * @return {@code true} if this sort defines byte code.
542
                 */
543
                public boolean isImplemented() {
544
                    return implement;
1✔
545
                }
546
            }
547

548
            /**
549
             * A canonical implementation of a method that is not declared but inherited by the instrumented type.
550
             */
551
            @HashCodeAndEqualsPlugin.Enhance
552
            class ForNonImplementedMethod implements Record {
553

554
                /**
555
                 * The undefined method.
556
                 */
557
                private final MethodDescription methodDescription;
558

559
                /**
560
                 * Creates a new undefined record.
561
                 *
562
                 * @param methodDescription The undefined method.
563
                 */
564
                public ForNonImplementedMethod(MethodDescription methodDescription) {
1✔
565
                    this.methodDescription = methodDescription;
1✔
566
                }
1✔
567

568
                /**
569
                 * {@inheritDoc}
570
                 */
571
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
572
                    /* do nothing */
573
                }
1✔
574

575
                /**
576
                 * {@inheritDoc}
577
                 */
578
                public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
579
                    throw new IllegalStateException("Cannot apply body for non-implemented method on " + methodDescription);
1✔
580
                }
581

582
                /**
583
                 * {@inheritDoc}
584
                 */
585
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
586
                    /* do nothing */
587
                }
1✔
588

589
                /**
590
                 * {@inheritDoc}
591
                 */
592
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
593
                    throw new IllegalStateException("Cannot apply code for non-implemented method on " + methodDescription);
×
594
                }
595

596
                /**
597
                 * {@inheritDoc}
598
                 */
599
                public void applyHead(MethodVisitor methodVisitor) {
600
                    throw new IllegalStateException("Cannot apply head for non-implemented method on " + methodDescription);
1✔
601
                }
602

603
                /**
604
                 * {@inheritDoc}
605
                 */
606
                public MethodDescription getMethod() {
607
                    return methodDescription;
1✔
608
                }
609

610
                /**
611
                 * {@inheritDoc}
612
                 */
613
                public Visibility getVisibility() {
614
                    return methodDescription.getVisibility();
×
615
                }
616

617
                /**
618
                 * {@inheritDoc}
619
                 */
620
                public Sort getSort() {
621
                    return Sort.SKIPPED;
1✔
622
                }
623

624
                /**
625
                 * {@inheritDoc}
626
                 */
627
                public Record prepend(ByteCodeAppender byteCodeAppender) {
628
                    return new ForDefinedMethod.WithBody(methodDescription, new ByteCodeAppender.Compound(byteCodeAppender,
1✔
629
                            new ByteCodeAppender.Simple(DefaultValue.of(methodDescription.getReturnType()), MethodReturn.of(methodDescription.getReturnType()))));
1✔
630
                }
631
            }
632

633
            /**
634
             * A base implementation of an abstract entry that defines a method.
635
             */
636
            abstract class ForDefinedMethod implements Record {
1✔
637

638
                /**
639
                 * {@inheritDoc}
640
                 */
641
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
642
                    MethodVisitor methodVisitor = classVisitor.visitMethod(getMethod().getActualModifiers(getSort().isImplemented(), getVisibility()),
1✔
643
                            getMethod().getInternalName(),
1✔
644
                            getMethod().getDescriptor(),
1✔
645
                            getMethod().getGenericSignature(),
1✔
646
                            getMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
647
                    if (methodVisitor != null) {
1✔
648
                        ParameterList<?> parameterList = getMethod().getParameters();
1✔
649
                        if (parameterList.hasExplicitMetaData()) {
1✔
650
                            for (ParameterDescription parameterDescription : parameterList) {
1✔
651
                                methodVisitor.visitParameter(parameterDescription.getName(), parameterDescription.getModifiers());
1✔
652
                            }
1✔
653
                        }
654
                        applyHead(methodVisitor);
1✔
655
                        applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
656
                        methodVisitor.visitEnd();
1✔
657
                    }
658
                }
1✔
659

660
                /**
661
                 * Describes an entry that defines a method as byte code.
662
                 */
663
                @HashCodeAndEqualsPlugin.Enhance
664
                public static class WithBody extends ForDefinedMethod {
665

666
                    /**
667
                     * The implemented method.
668
                     */
669
                    private final MethodDescription methodDescription;
670

671
                    /**
672
                     * The byte code appender to apply.
673
                     */
674
                    private final ByteCodeAppender byteCodeAppender;
675

676
                    /**
677
                     * The method attribute appender to apply.
678
                     */
679
                    private final MethodAttributeAppender methodAttributeAppender;
680

681
                    /**
682
                     * The represented method's minimum visibility.
683
                     */
684
                    private final Visibility visibility;
685

686
                    /**
687
                     * Creates a new record for an implemented method without attributes or a modifier resolver.
688
                     *
689
                     * @param methodDescription The implemented method.
690
                     * @param byteCodeAppender  The byte code appender to apply.
691
                     */
692
                    public WithBody(MethodDescription methodDescription, ByteCodeAppender byteCodeAppender) {
693
                        this(methodDescription, byteCodeAppender, MethodAttributeAppender.NoOp.INSTANCE, methodDescription.getVisibility());
1✔
694
                    }
1✔
695

696
                    /**
697
                     * Creates a new entry for a method that defines a method as byte code.
698
                     *
699
                     * @param methodDescription       The implemented method.
700
                     * @param byteCodeAppender        The byte code appender to apply.
701
                     * @param methodAttributeAppender The method attribute appender to apply.
702
                     * @param visibility              The represented method's minimum visibility.
703
                     */
704
                    public WithBody(MethodDescription methodDescription,
705
                                    ByteCodeAppender byteCodeAppender,
706
                                    MethodAttributeAppender methodAttributeAppender,
707
                                    Visibility visibility) {
1✔
708
                        this.methodDescription = methodDescription;
1✔
709
                        this.byteCodeAppender = byteCodeAppender;
1✔
710
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
711
                        this.visibility = visibility;
1✔
712
                    }
1✔
713

714
                    /**
715
                     * {@inheritDoc}
716
                     */
717
                    public MethodDescription getMethod() {
718
                        return methodDescription;
1✔
719
                    }
720

721
                    /**
722
                     * {@inheritDoc}
723
                     */
724
                    public Sort getSort() {
725
                        return Sort.IMPLEMENTED;
1✔
726
                    }
727

728
                    /**
729
                     * {@inheritDoc}
730
                     */
731
                    public Visibility getVisibility() {
732
                        return visibility;
1✔
733
                    }
734

735
                    /**
736
                     * {@inheritDoc}
737
                     */
738
                    public void applyHead(MethodVisitor methodVisitor) {
739
                        /* do nothing */
740
                    }
1✔
741

742
                    /**
743
                     * {@inheritDoc}
744
                     */
745
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
746
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
747
                        methodVisitor.visitCode();
1✔
748
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
749
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
750
                    }
1✔
751

752
                    /**
753
                     * {@inheritDoc}
754
                     */
755
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
756
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
757
                    }
1✔
758

759
                    /**
760
                     * {@inheritDoc}
761
                     */
762
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
763
                        return byteCodeAppender.apply(methodVisitor, implementationContext, methodDescription);
1✔
764
                    }
765

766
                    /**
767
                     * {@inheritDoc}
768
                     */
769
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
770
                        return new WithBody(methodDescription,
1✔
771
                                new ByteCodeAppender.Compound(byteCodeAppender, this.byteCodeAppender),
772
                                methodAttributeAppender,
773
                                visibility);
774
                    }
775
                }
776

777
                /**
778
                 * Describes an entry that defines a method but without byte code and without an annotation value.
779
                 */
780
                @HashCodeAndEqualsPlugin.Enhance
781
                public static class WithoutBody extends ForDefinedMethod {
782

783
                    /**
784
                     * The implemented method.
785
                     */
786
                    private final MethodDescription methodDescription;
787

788
                    /**
789
                     * The method attribute appender to apply.
790
                     */
791
                    private final MethodAttributeAppender methodAttributeAppender;
792

793
                    /**
794
                     * The represented method's minimum visibility.
795
                     */
796
                    private final Visibility visibility;
797

798
                    /**
799
                     * Creates a new entry for a method that is defines but does not append byte code, i.e. is native or abstract.
800
                     *
801
                     * @param methodDescription       The implemented method.
802
                     * @param methodAttributeAppender The method attribute appender to apply.
803
                     * @param visibility              The represented method's minimum visibility.
804
                     */
805
                    public WithoutBody(MethodDescription methodDescription, MethodAttributeAppender methodAttributeAppender, Visibility visibility) {
1✔
806
                        this.methodDescription = methodDescription;
1✔
807
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
808
                        this.visibility = visibility;
1✔
809
                    }
1✔
810

811
                    /**
812
                     * {@inheritDoc}
813
                     */
814
                    public MethodDescription getMethod() {
815
                        return methodDescription;
1✔
816
                    }
817

818
                    /**
819
                     * {@inheritDoc}
820
                     */
821
                    public Sort getSort() {
822
                        return Sort.DEFINED;
1✔
823
                    }
824

825
                    /**
826
                     * {@inheritDoc}
827
                     */
828
                    public Visibility getVisibility() {
829
                        return visibility;
1✔
830
                    }
831

832
                    /**
833
                     * {@inheritDoc}
834
                     */
835
                    public void applyHead(MethodVisitor methodVisitor) {
836
                        /* do nothing */
837
                    }
1✔
838

839
                    /**
840
                     * {@inheritDoc}
841
                     */
842
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
843
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
844
                    }
1✔
845

846
                    /**
847
                     * {@inheritDoc}
848
                     */
849
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
850
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
851
                    }
1✔
852

853
                    /**
854
                     * {@inheritDoc}
855
                     */
856
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
857
                        throw new IllegalStateException("Cannot apply code for abstract method on " + methodDescription);
1✔
858
                    }
859

860
                    /**
861
                     * {@inheritDoc}
862
                     */
863
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
864
                        throw new IllegalStateException("Cannot prepend code for abstract method on " + methodDescription);
1✔
865
                    }
866
                }
867

868
                /**
869
                 * Describes an entry that defines a method with a default annotation value.
870
                 */
871
                @HashCodeAndEqualsPlugin.Enhance
872
                public static class WithAnnotationDefaultValue extends ForDefinedMethod {
873

874
                    /**
875
                     * The implemented method.
876
                     */
877
                    private final MethodDescription methodDescription;
878

879
                    /**
880
                     * The annotation value to define.
881
                     */
882
                    private final AnnotationValue<?, ?> annotationValue;
883

884
                    /**
885
                     * The method attribute appender to apply.
886
                     */
887
                    private final MethodAttributeAppender methodAttributeAppender;
888

889
                    /**
890
                     * Creates a new entry for defining a method with a default annotation value.
891
                     *
892
                     * @param methodDescription       The implemented method.
893
                     * @param annotationValue         The annotation value to define.
894
                     * @param methodAttributeAppender The method attribute appender to apply.
895
                     */
896
                    public WithAnnotationDefaultValue(MethodDescription methodDescription,
897
                                                      AnnotationValue<?, ?> annotationValue,
898
                                                      MethodAttributeAppender methodAttributeAppender) {
1✔
899
                        this.methodDescription = methodDescription;
1✔
900
                        this.annotationValue = annotationValue;
1✔
901
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
902
                    }
1✔
903

904
                    /**
905
                     * {@inheritDoc}
906
                     */
907
                    public MethodDescription getMethod() {
908
                        return methodDescription;
1✔
909
                    }
910

911
                    /**
912
                     * {@inheritDoc}
913
                     */
914
                    public Sort getSort() {
915
                        return Sort.DEFINED;
1✔
916
                    }
917

918
                    /**
919
                     * {@inheritDoc}
920
                     */
921
                    public Visibility getVisibility() {
922
                        return methodDescription.getVisibility();
1✔
923
                    }
924

925
                    /**
926
                     * {@inheritDoc}
927
                     */
928
                    public void applyHead(MethodVisitor methodVisitor) {
929
                        if (!methodDescription.isDefaultValue(annotationValue)) {
1✔
930
                            throw new IllegalStateException("Cannot set " + annotationValue + " as default for " + methodDescription);
1✔
931
                        }
932
                        AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
1✔
933
                        AnnotationAppender.Default.apply(annotationVisitor,
1✔
934
                                methodDescription.getReturnType().asErasure(),
1✔
935
                                AnnotationAppender.NO_NAME,
936
                                annotationValue.resolve());
1✔
937
                        annotationVisitor.visitEnd();
1✔
938
                    }
1✔
939

940
                    /**
941
                     * {@inheritDoc}
942
                     */
943
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
944
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
945
                    }
1✔
946

947
                    /**
948
                     * {@inheritDoc}
949
                     */
950
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
951
                        throw new IllegalStateException("Cannot apply attributes for default value on " + methodDescription);
1✔
952
                    }
953

954
                    /**
955
                     * {@inheritDoc}
956
                     */
957
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
958
                        throw new IllegalStateException("Cannot apply code for default value on " + methodDescription);
1✔
959
                    }
960

961
                    /**
962
                     * {@inheritDoc}
963
                     */
964
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
965
                        throw new IllegalStateException("Cannot prepend code for default value on " + methodDescription);
1✔
966
                    }
967
                }
968

969
                /**
970
                 * A record for a visibility bridge.
971
                 */
972
                @HashCodeAndEqualsPlugin.Enhance
973
                public static class OfVisibilityBridge extends ForDefinedMethod implements ByteCodeAppender {
974

975
                    /**
976
                     * The visibility bridge.
977
                     */
978
                    private final MethodDescription visibilityBridge;
979

980
                    /**
981
                     * The method the visibility bridge invokes.
982
                     */
983
                    private final MethodDescription bridgeTarget;
984

985
                    /**
986
                     * The type on which the bridge method is invoked.
987
                     */
988
                    private final TypeDescription bridgeType;
989

990
                    /**
991
                     * The attribute appender to apply to the visibility bridge.
992
                     */
993
                    private final MethodAttributeAppender attributeAppender;
994

995
                    /**
996
                     * Creates a new record for a visibility bridge.
997
                     *
998
                     * @param visibilityBridge  The visibility bridge.
999
                     * @param bridgeTarget      The method the visibility bridge invokes.
1000
                     * @param bridgeType        The type of the instrumented type.
1001
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
1002
                     */
1003
                    protected OfVisibilityBridge(MethodDescription visibilityBridge,
1004
                                                 MethodDescription bridgeTarget,
1005
                                                 TypeDescription bridgeType,
1006
                                                 MethodAttributeAppender attributeAppender) {
1✔
1007
                        this.visibilityBridge = visibilityBridge;
1✔
1008
                        this.bridgeTarget = bridgeTarget;
1✔
1009
                        this.bridgeType = bridgeType;
1✔
1010
                        this.attributeAppender = attributeAppender;
1✔
1011
                    }
1✔
1012

1013
                    /**
1014
                     * Creates a record for a visibility bridge.
1015
                     *
1016
                     * @param instrumentedType  The instrumented type.
1017
                     * @param bridgeTarget      The target method of the visibility bridge.
1018
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
1019
                     * @return A record describing the visibility bridge.
1020
                     */
1021
                    public static Record of(TypeDescription instrumentedType, MethodDescription bridgeTarget, MethodAttributeAppender attributeAppender) {
1022
                        // Default method bridges must be dispatched on an implemented interface type, not considering the declaring type.
1023
                        TypeDefinition bridgeType = null;
1✔
1024
                        if (bridgeTarget.isDefaultMethod()) {
1✔
1025
                            TypeDescription declaringType = bridgeTarget.getDeclaringType().asErasure();
1✔
1026
                            for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures().filter(isSubTypeOf(declaringType))) {
1✔
1027
                                if (bridgeType == null || declaringType.isAssignableTo(bridgeType.asErasure())) {
1✔
1028
                                    bridgeType = interfaceType;
1✔
1029
                                }
1030
                            }
1✔
1031
                        }
1032
                        // Non-default method or default method that is inherited by a super class.
1033
                        if (bridgeType == null) {
1✔
1034
                            bridgeType = instrumentedType.getSuperClass();
1✔
1035
                            if (bridgeType == null) {
1✔
1036
                                bridgeType = TypeDescription.ForLoadedType.of(Object.class);
×
1037
                            }
1038
                        }
1039
                        return new OfVisibilityBridge(new VisibilityBridge(instrumentedType, bridgeTarget),
1✔
1040
                                bridgeTarget,
1041
                                bridgeType.asErasure(),
1✔
1042
                                attributeAppender);
1043
                    }
1044

1045
                    /**
1046
                     * {@inheritDoc}
1047
                     */
1048
                    public MethodDescription getMethod() {
1049
                        return visibilityBridge;
1✔
1050
                    }
1051

1052
                    /**
1053
                     * {@inheritDoc}
1054
                     */
1055
                    public Sort getSort() {
1056
                        return Sort.IMPLEMENTED;
1✔
1057
                    }
1058

1059
                    /**
1060
                     * {@inheritDoc}
1061
                     */
1062
                    public Visibility getVisibility() {
1063
                        return bridgeTarget.getVisibility();
1✔
1064
                    }
1065

1066
                    /**
1067
                     * {@inheritDoc}
1068
                     */
1069
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
1070
                        return new ForDefinedMethod.WithBody(visibilityBridge,
1✔
1071
                                new ByteCodeAppender.Compound(this, byteCodeAppender),
1072
                                attributeAppender,
1073
                                bridgeTarget.getVisibility());
1✔
1074
                    }
1075

1076
                    /**
1077
                     * {@inheritDoc}
1078
                     */
1079
                    public void applyHead(MethodVisitor methodVisitor) {
1080
                        /* do nothing */
1081
                    }
1✔
1082

1083
                    /**
1084
                     * {@inheritDoc}
1085
                     */
1086
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1087
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1088
                        methodVisitor.visitCode();
1✔
1089
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
1090
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1091
                    }
1✔
1092

1093
                    /**
1094
                     * {@inheritDoc}
1095
                     */
1096
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1097
                        attributeAppender.apply(methodVisitor, visibilityBridge, annotationValueFilterFactory.on(visibilityBridge));
1✔
1098
                    }
1✔
1099

1100
                    /**
1101
                     * {@inheritDoc}
1102
                     */
1103
                    public Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1104
                        return apply(methodVisitor, implementationContext, visibilityBridge);
1✔
1105
                    }
1106

1107
                    /**
1108
                     * {@inheritDoc}
1109
                     */
1110
                    public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1111
                        return new ByteCodeAppender.Simple(
1✔
1112
                                MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1✔
1113
                                MethodInvocation.invoke(bridgeTarget).special(bridgeType),
1✔
1114
                                MethodReturn.of(instrumentedMethod.getReturnType())
1✔
1115
                        ).apply(methodVisitor, implementationContext, instrumentedMethod);
1✔
1116
                    }
1117

1118
                    /**
1119
                     * A method describing a visibility bridge.
1120
                     */
1121
                    protected static class VisibilityBridge extends MethodDescription.InDefinedShape.AbstractBase {
1122

1123
                        /**
1124
                         * The instrumented type.
1125
                         */
1126
                        private final TypeDescription instrumentedType;
1127

1128
                        /**
1129
                         * The method that is the target of the bridge.
1130
                         */
1131
                        private final MethodDescription bridgeTarget;
1132

1133
                        /**
1134
                         * Creates a new visibility bridge.
1135
                         *
1136
                         * @param instrumentedType The instrumented type.
1137
                         * @param bridgeTarget     The method that is the target of the bridge.
1138
                         */
1139
                        protected VisibilityBridge(TypeDescription instrumentedType, MethodDescription bridgeTarget) {
1✔
1140
                            this.instrumentedType = instrumentedType;
1✔
1141
                            this.bridgeTarget = bridgeTarget;
1✔
1142
                        }
1✔
1143

1144
                        /**
1145
                         * {@inheritDoc}
1146
                         */
1147
                        @Nonnull
1148
                        public TypeDescription getDeclaringType() {
1149
                            return instrumentedType;
1✔
1150
                        }
1151

1152
                        /**
1153
                         * {@inheritDoc}
1154
                         */
1155
                        public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1156
                            return new ParameterList.Explicit.ForTypes(this, bridgeTarget.getParameters().asTypeList().asRawTypes());
1✔
1157
                        }
1158

1159
                        /**
1160
                         * {@inheritDoc}
1161
                         */
1162
                        public TypeDescription.Generic getReturnType() {
1163
                            return bridgeTarget.getReturnType().asRawType();
1✔
1164
                        }
1165

1166
                        /**
1167
                         * {@inheritDoc}
1168
                         */
1169
                        public TypeList.Generic getExceptionTypes() {
1170
                            return bridgeTarget.getExceptionTypes().asRawTypes();
1✔
1171
                        }
1172

1173
                        /**
1174
                         * {@inheritDoc}
1175
                         */
1176
                        @MaybeNull
1177
                        public AnnotationValue<?, ?> getDefaultValue() {
1178
                            return AnnotationValue.UNDEFINED;
×
1179
                        }
1180

1181
                        /**
1182
                         * {@inheritDoc}
1183
                         */
1184
                        public TypeList.Generic getTypeVariables() {
1185
                            return new TypeList.Generic.Empty();
1✔
1186
                        }
1187

1188
                        /**
1189
                         * {@inheritDoc}
1190
                         */
1191
                        public AnnotationList getDeclaredAnnotations() {
1192
                            return bridgeTarget.getDeclaredAnnotations();
1✔
1193
                        }
1194

1195
                        /**
1196
                         * {@inheritDoc}
1197
                         */
1198
                        public int getModifiers() {
1199
                            return (bridgeTarget.getModifiers() | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE) & ~Opcodes.ACC_NATIVE;
1✔
1200
                        }
1201

1202
                        /**
1203
                         * {@inheritDoc}
1204
                         */
1205
                        public String getInternalName() {
1206
                            return bridgeTarget.getName();
1✔
1207
                        }
1208
                    }
1209
                }
1210
            }
1211

1212
            /**
1213
             * A wrapper that appends accessor bridges for a method's implementation. The bridges are only added if
1214
             * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool.Record#apply(ClassVisitor, Implementation.Context, AnnotationValueFilter.Factory)}
1215
             * is invoked such that bridges are not appended for methods that are rebased or redefined as such types already have bridge methods in place.
1216
             */
1217
            @HashCodeAndEqualsPlugin.Enhance
1218
            class AccessBridgeWrapper implements Record {
1219

1220
                /**
1221
                 * The delegate for implementing the bridge's target.
1222
                 */
1223
                private final Record delegate;
1224

1225
                /**
1226
                 * The instrumented type that defines the bridge methods and the bridge target.
1227
                 */
1228
                private final TypeDescription instrumentedType;
1229

1230
                /**
1231
                 * The target of the bridge method.
1232
                 */
1233
                private final MethodDescription bridgeTarget;
1234

1235
                /**
1236
                 * A collection of all tokens representing all bridge methods.
1237
                 */
1238
                private final Set<MethodDescription.TypeToken> bridgeTypes;
1239

1240
                /**
1241
                 * The attribute appender being applied for the bridge target.
1242
                 */
1243
                private final MethodAttributeAppender attributeAppender;
1244

1245
                /**
1246
                 * Creates a wrapper for adding accessor bridges.
1247
                 *
1248
                 * @param delegate          The delegate for implementing the bridge's target.
1249
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1250
                 * @param bridgeTarget      The target of the bridge method.
1251
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1252
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1253
                 */
1254
                protected AccessBridgeWrapper(Record delegate,
1255
                                              TypeDescription instrumentedType,
1256
                                              MethodDescription bridgeTarget,
1257
                                              Set<MethodDescription.TypeToken> bridgeTypes,
1258
                                              MethodAttributeAppender attributeAppender) {
1✔
1259
                    this.delegate = delegate;
1✔
1260
                    this.instrumentedType = instrumentedType;
1✔
1261
                    this.bridgeTarget = bridgeTarget;
1✔
1262
                    this.bridgeTypes = bridgeTypes;
1✔
1263
                    this.attributeAppender = attributeAppender;
1✔
1264
                }
1✔
1265

1266
                /**
1267
                 * Wraps the given record in an accessor bridge wrapper if necessary.
1268
                 *
1269
                 * @param delegate          The delegate for implementing the bridge's target.
1270
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1271
                 * @param bridgeTarget      The bridge methods' target methods.
1272
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1273
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1274
                 * @return The given record wrapped by a bridge method wrapper if necessary.
1275
                 */
1276
                public static Record of(Record delegate,
1277
                                        TypeDescription instrumentedType,
1278
                                        MethodDescription bridgeTarget,
1279
                                        Set<MethodDescription.TypeToken> bridgeTypes,
1280
                                        MethodAttributeAppender attributeAppender) {
1281
                    Set<MethodDescription.TypeToken> compatibleBridgeTypes = new HashSet<MethodDescription.TypeToken>();
1✔
1282
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1283
                        if (bridgeTarget.isBridgeCompatible(bridgeType)) {
1✔
1284
                            compatibleBridgeTypes.add(bridgeType);
1✔
1285
                        }
1286
                    }
1✔
1287
                    return compatibleBridgeTypes.isEmpty() || (instrumentedType.isInterface() && !delegate.getSort().isImplemented())
1✔
1288
                            ? delegate
1289
                            : new AccessBridgeWrapper(delegate, instrumentedType, bridgeTarget, compatibleBridgeTypes, attributeAppender);
1290
                }
1291

1292
                /**
1293
                 * {@inheritDoc}
1294
                 */
1295
                public Sort getSort() {
1296
                    return delegate.getSort();
1✔
1297
                }
1298

1299
                /**
1300
                 * {@inheritDoc}
1301
                 */
1302
                public MethodDescription getMethod() {
1303
                    return bridgeTarget;
×
1304
                }
1305

1306
                /**
1307
                 * {@inheritDoc}
1308
                 */
1309
                public Visibility getVisibility() {
1310
                    return delegate.getVisibility();
1✔
1311
                }
1312

1313
                /**
1314
                 * {@inheritDoc}
1315
                 */
1316
                public Record prepend(ByteCodeAppender byteCodeAppender) {
1317
                    return new AccessBridgeWrapper(delegate.prepend(byteCodeAppender), instrumentedType, bridgeTarget, bridgeTypes, attributeAppender);
1✔
1318
                }
1319

1320
                /**
1321
                 * {@inheritDoc}
1322
                 */
1323
                public void apply(ClassVisitor classVisitor,
1324
                                  Implementation.Context implementationContext,
1325
                                  AnnotationValueFilter.Factory annotationValueFilterFactory) {
1326
                    delegate.apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
1327
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1328
                        MethodDescription.InDefinedShape bridgeMethod = new AccessorBridge(bridgeTarget, bridgeType, instrumentedType);
1✔
1329
                        MethodDescription.InDefinedShape bridgeTarget = new BridgeTarget(this.bridgeTarget, instrumentedType);
1✔
1330
                        MethodVisitor methodVisitor = classVisitor.visitMethod(bridgeMethod.getActualModifiers(true, getVisibility()),
1✔
1331
                                bridgeMethod.getInternalName(),
1✔
1332
                                bridgeMethod.getDescriptor(),
1✔
1333
                                MethodDescription.NON_GENERIC_SIGNATURE,
1334
                                bridgeMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
1335
                        if (methodVisitor != null) {
1✔
1336
                            attributeAppender.apply(methodVisitor, bridgeMethod, annotationValueFilterFactory.on(instrumentedType));
1✔
1337
                            methodVisitor.visitCode();
1✔
1338
                            ByteCodeAppender.Size size = new ByteCodeAppender.Simple(
1✔
1339
                                    MethodVariableAccess.allArgumentsOf(bridgeMethod).asBridgeOf(bridgeTarget).prependThisReference(),
1✔
1340
                                    MethodInvocation.invoke(bridgeTarget).virtual(instrumentedType),
1✔
1341
                                    bridgeTarget.getReturnType().asErasure().isAssignableTo(bridgeMethod.getReturnType().asErasure())
1✔
1342
                                            ? StackManipulation.Trivial.INSTANCE
1343
                                            : TypeCasting.to(bridgeMethod.getReturnType().asErasure()),
1✔
1344
                                    MethodReturn.of(bridgeMethod.getReturnType())
1✔
1345
                            ).apply(methodVisitor, implementationContext, bridgeMethod);
1✔
1346
                            methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1347
                            methodVisitor.visitEnd();
1✔
1348
                        }
1349
                    }
1✔
1350
                }
1✔
1351

1352
                /**
1353
                 * {@inheritDoc}
1354
                 */
1355
                public void applyHead(MethodVisitor methodVisitor) {
1356
                    delegate.applyHead(methodVisitor);
1✔
1357
                }
1✔
1358

1359
                /**
1360
                 * {@inheritDoc}
1361
                 */
1362
                public void applyBody(MethodVisitor methodVisitor,
1363
                                      Implementation.Context implementationContext,
1364
                                      AnnotationValueFilter.Factory annotationValueFilterFactory) {
1365
                    delegate.applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
1366
                }
1✔
1367

1368
                /**
1369
                 * {@inheritDoc}
1370
                 */
1371
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1372
                    delegate.applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1373
                }
1✔
1374

1375
                /**
1376
                 * {@inheritDoc}
1377
                 */
1378
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1379
                    return delegate.applyCode(methodVisitor, implementationContext);
1✔
1380
                }
1381

1382
                /**
1383
                 * A method representing an accessor bridge method.
1384
                 */
1385
                protected static class AccessorBridge extends MethodDescription.InDefinedShape.AbstractBase {
1386

1387
                    /**
1388
                     * The target method of the bridge.
1389
                     */
1390
                    private final MethodDescription bridgeTarget;
1391

1392
                    /**
1393
                     * The bridge's type token.
1394
                     */
1395
                    private final MethodDescription.TypeToken bridgeType;
1396

1397
                    /**
1398
                     * The instrumented type defining the bridge target.
1399
                     */
1400
                    private final TypeDescription instrumentedType;
1401

1402
                    /**
1403
                     * Creates a new accessor bridge method.
1404
                     *
1405
                     * @param bridgeTarget     The target method of the bridge.
1406
                     * @param bridgeType       The bridge's type token.
1407
                     * @param instrumentedType The instrumented type defining the bridge target.
1408
                     */
1409
                    protected AccessorBridge(MethodDescription bridgeTarget, TypeToken bridgeType, TypeDescription instrumentedType) {
1✔
1410
                        this.bridgeTarget = bridgeTarget;
1✔
1411
                        this.bridgeType = bridgeType;
1✔
1412
                        this.instrumentedType = instrumentedType;
1✔
1413
                    }
1✔
1414

1415
                    /**
1416
                     * {@inheritDoc}
1417
                     */
1418
                    @Nonnull
1419
                    public TypeDescription getDeclaringType() {
1420
                        return instrumentedType;
1✔
1421
                    }
1422

1423
                    /**
1424
                     * {@inheritDoc}
1425
                     */
1426
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1427
                        return new ParameterList.Explicit.ForTypes(this, bridgeType.getParameterTypes());
1✔
1428
                    }
1429

1430
                    /**
1431
                     * {@inheritDoc}
1432
                     */
1433
                    public TypeDescription.Generic getReturnType() {
1434
                        return bridgeType.getReturnType().asGenericType();
1✔
1435
                    }
1436

1437
                    /**
1438
                     * {@inheritDoc}
1439
                     */
1440
                    public TypeList.Generic getExceptionTypes() {
1441
                        return bridgeTarget.getExceptionTypes().accept(TypeDescription.Generic.Visitor.TypeErasing.INSTANCE);
1✔
1442
                    }
1443

1444
                    /**
1445
                     * {@inheritDoc}
1446
                     */
1447
                    @MaybeNull
1448
                    public AnnotationValue<?, ?> getDefaultValue() {
1449
                        return AnnotationValue.UNDEFINED;
×
1450
                    }
1451

1452
                    /**
1453
                     * {@inheritDoc}
1454
                     */
1455
                    public TypeList.Generic getTypeVariables() {
1456
                        return new TypeList.Generic.Empty();
1✔
1457
                    }
1458

1459
                    /**
1460
                     * {@inheritDoc}
1461
                     */
1462
                    public AnnotationList getDeclaredAnnotations() {
1463
                        return new AnnotationList.Empty();
1✔
1464
                    }
1465

1466
                    /**
1467
                     * {@inheritDoc}
1468
                     */
1469
                    public int getModifiers() {
1470
                        return (bridgeTarget.getModifiers() | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC) & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE);
1✔
1471
                    }
1472

1473
                    /**
1474
                     * {@inheritDoc}
1475
                     */
1476
                    public String getInternalName() {
1477
                        return bridgeTarget.getInternalName();
1✔
1478
                    }
1479
                }
1480

1481
                /**
1482
                 * A method representing a bridge's target method in its defined shape.
1483
                 */
1484
                protected static class BridgeTarget extends MethodDescription.InDefinedShape.AbstractBase {
1485

1486
                    /**
1487
                     * The target method of the bridge.
1488
                     */
1489
                    private final MethodDescription bridgeTarget;
1490

1491
                    /**
1492
                     * The instrumented type defining the bridge target.
1493
                     */
1494
                    private final TypeDescription instrumentedType;
1495

1496
                    /**
1497
                     * Creates a new bridge target.
1498
                     *
1499
                     * @param bridgeTarget     The target method of the bridge.
1500
                     * @param instrumentedType The instrumented type defining the bridge target.
1501
                     */
1502
                    protected BridgeTarget(MethodDescription bridgeTarget, TypeDescription instrumentedType) {
1✔
1503
                        this.bridgeTarget = bridgeTarget;
1✔
1504
                        this.instrumentedType = instrumentedType;
1✔
1505
                    }
1✔
1506

1507
                    /**
1508
                     * {@inheritDoc}
1509
                     */
1510
                    @Nonnull
1511
                    public TypeDescription getDeclaringType() {
1512
                        return instrumentedType;
1✔
1513
                    }
1514

1515
                    /**
1516
                     * {@inheritDoc}
1517
                     */
1518
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1519
                        return new ParameterList.ForTokens(this, bridgeTarget.getParameters().asTokenList(is(instrumentedType)));
1✔
1520
                    }
1521

1522
                    /**
1523
                     * {@inheritDoc}
1524
                     */
1525
                    public TypeDescription.Generic getReturnType() {
1526
                        return bridgeTarget.getReturnType();
1✔
1527
                    }
1528

1529
                    /**
1530
                     * {@inheritDoc}
1531
                     */
1532
                    public TypeList.Generic getExceptionTypes() {
1533
                        return bridgeTarget.getExceptionTypes();
×
1534
                    }
1535

1536
                    /**
1537
                     * {@inheritDoc}
1538
                     */
1539
                    @MaybeNull
1540
                    public AnnotationValue<?, ?> getDefaultValue() {
1541
                        return bridgeTarget.getDefaultValue();
×
1542
                    }
1543

1544
                    /**
1545
                     * {@inheritDoc}
1546
                     */
1547
                    public TypeList.Generic getTypeVariables() {
1548
                        return bridgeTarget.getTypeVariables();
×
1549
                    }
1550

1551
                    /**
1552
                     * {@inheritDoc}
1553
                     */
1554
                    public AnnotationList getDeclaredAnnotations() {
1555
                        return bridgeTarget.getDeclaredAnnotations();
×
1556
                    }
1557

1558
                    /**
1559
                     * {@inheritDoc}
1560
                     */
1561
                    public int getModifiers() {
1562
                        return bridgeTarget.getModifiers();
1✔
1563
                    }
1564

1565
                    /**
1566
                     * {@inheritDoc}
1567
                     */
1568
                    public String getInternalName() {
1569
                        return bridgeTarget.getInternalName();
1✔
1570
                    }
1571
                }
1572
            }
1573
        }
1574
    }
1575

1576
    /**
1577
     * An record component pool that allows a lookup for how to implement a record component.
1578
     */
1579
    interface RecordComponentPool {
1580

1581
        /**
1582
         * Looks up a handler entry for a given record component.
1583
         *
1584
         * @param recordComponentDescription The record component being processed.
1585
         * @return A handler entry for the given record component.
1586
         */
1587
        Record target(RecordComponentDescription recordComponentDescription);
1588

1589
        /**
1590
         * An entry of a record component pool that describes how a record component is implemented.
1591
         *
1592
         * @see RecordComponentPool
1593
         */
1594
        interface Record {
1595

1596
            /**
1597
             * Determines if this record is implicit, i.e is not defined by a {@link RecordComponentPool}.
1598
             *
1599
             * @return {@code true} if this record is implicit.
1600
             */
1601
            boolean isImplicit();
1602

1603
            /**
1604
             * Returns the record component that this record represents.
1605
             *
1606
             * @return The record component that this record represents.
1607
             */
1608
            RecordComponentDescription getRecordComponent();
1609

1610
            /**
1611
             * Returns the record component attribute appender for a given record component.
1612
             *
1613
             * @return The record component appender to be applied on the given field.
1614
             */
1615
            RecordComponentAttributeAppender getRecordComponentAppender();
1616

1617
            /**
1618
             * Writes this record to a given class visitor.
1619
             *
1620
             * @param classVisitor                 The class visitor to which this record is to be written to.
1621
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
1622
             */
1623
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1624

1625
            /**
1626
             * Applies this record to a record component visitor. This is not possible for implicit records.
1627
             *
1628
             * @param recordComponentVisitor       The record component visitor onto which this record is to be applied.
1629
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
1630
             */
1631
            void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1632

1633
            /**
1634
             * A record for a simple field without a default value where all of the record component's declared annotations are appended.
1635
             */
1636
            @HashCodeAndEqualsPlugin.Enhance
1637
            class ForImplicitRecordComponent implements Record {
1638

1639
                /**
1640
                 * The implemented record component.
1641
                 */
1642
                private final RecordComponentDescription recordComponentDescription;
1643

1644
                /**
1645
                 * Creates a new record for a simple record component.
1646
                 *
1647
                 * @param recordComponentDescription The described record component.
1648
                 */
1649
                public ForImplicitRecordComponent(RecordComponentDescription recordComponentDescription) {
1✔
1650
                    this.recordComponentDescription = recordComponentDescription;
1✔
1651
                }
1✔
1652

1653
                /**
1654
                 * {@inheritDoc}
1655
                 */
1656
                public boolean isImplicit() {
1657
                    return true;
1✔
1658
                }
1659

1660
                /**
1661
                 * {@inheritDoc}
1662
                 */
1663
                public RecordComponentDescription getRecordComponent() {
1664
                    return recordComponentDescription;
×
1665
                }
1666

1667
                /**
1668
                 * {@inheritDoc}
1669
                 */
1670
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1671
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
×
1672
                }
1673

1674
                /**
1675
                 * {@inheritDoc}
1676
                 */
1677
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1678
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1679
                            recordComponentDescription.getDescriptor(),
1✔
1680
                            recordComponentDescription.getGenericSignature());
1✔
1681
                    if (recordComponentVisitor != null) {
1✔
1682
                        RecordComponentAttributeAppender.ForInstrumentedRecordComponent.INSTANCE.apply(recordComponentVisitor,
1✔
1683
                                recordComponentDescription,
1684
                                annotationValueFilterFactory.on(recordComponentDescription));
1✔
1685
                        recordComponentVisitor.visitEnd();
1✔
1686
                    }
1687
                }
1✔
1688

1689
                /**
1690
                 * {@inheritDoc}
1691
                 */
1692
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1693
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
1694
                }
1695
            }
1696

1697
            /**
1698
             * A record for a rich record component with attributes.
1699
             */
1700
            @HashCodeAndEqualsPlugin.Enhance
1701
            class ForExplicitRecordComponent implements Record {
1702

1703
                /**
1704
                 * The attribute appender for the record component.
1705
                 */
1706
                private final RecordComponentAttributeAppender attributeAppender;
1707

1708
                /**
1709
                 * The implemented record component.
1710
                 */
1711
                private final RecordComponentDescription recordComponentDescription;
1712

1713
                /**
1714
                 * Creates a record for a rich record component.
1715
                 *
1716
                 * @param attributeAppender          The attribute appender for the record component.
1717
                 * @param recordComponentDescription The implemented record component.
1718
                 */
1719
                public ForExplicitRecordComponent(RecordComponentAttributeAppender attributeAppender, RecordComponentDescription recordComponentDescription) {
1✔
1720
                    this.attributeAppender = attributeAppender;
1✔
1721
                    this.recordComponentDescription = recordComponentDescription;
1✔
1722
                }
1✔
1723

1724
                /**
1725
                 * {@inheritDoc}
1726
                 */
1727
                public boolean isImplicit() {
1728
                    return false;
1✔
1729
                }
1730

1731
                /**
1732
                 * {@inheritDoc}
1733
                 */
1734
                public RecordComponentDescription getRecordComponent() {
1735
                    return recordComponentDescription;
×
1736
                }
1737

1738
                /**
1739
                 * {@inheritDoc}
1740
                 */
1741
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1742
                    return attributeAppender;
1✔
1743
                }
1744

1745
                /**
1746
                 * {@inheritDoc}
1747
                 */
1748
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1749
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1750
                            recordComponentDescription.getDescriptor(),
1✔
1751
                            recordComponentDescription.getGenericSignature());
1✔
1752
                    if (recordComponentVisitor != null) {
1✔
1753
                        attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1754
                        recordComponentVisitor.visitEnd();
1✔
1755
                    }
1756
                }
1✔
1757

1758
                /**
1759
                 * {@inheritDoc}
1760
                 */
1761
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1762
                    attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1763
                }
1✔
1764
            }
1765
        }
1766

1767
        /**
1768
         * A record component pool that does not allow any look ups.
1769
         */
1770
        enum Disabled implements RecordComponentPool {
1✔
1771

1772
            /**
1773
             * The singleton instance.
1774
             */
1775
            INSTANCE;
1✔
1776

1777
            /**
1778
             * {@inheritDoc}
1779
             */
1780
            public Record target(RecordComponentDescription recordComponentDescription) {
1781
                throw new IllegalStateException("Cannot look up record component from disabled pool");
1✔
1782
            }
1783
        }
1784
    }
1785

1786
    /**
1787
     * A default implementation of a {@link net.bytebuddy.dynamic.scaffold.TypeWriter}.
1788
     *
1789
     * @param <S> The best known loaded type for the dynamically created type.
1790
     */
1791
    @HashCodeAndEqualsPlugin.Enhance
1792
    abstract class Default<S> implements TypeWriter<S> {
1793

1794
        /**
1795
         * Indicates an empty reference in a class file which is expressed by {@code null}.
1796
         */
1797
        @AlwaysNull
1798
        private static final String NO_REFERENCE = null;
1✔
1799

1800
        /**
1801
         * A folder for dumping class files or {@code null} if no dump should be generated.
1802
         */
1803
        @MaybeNull
1804
        protected static final String DUMP_FOLDER;
1805

1806
        /*
1807
         * Reads the dumping property that is set at program start up. This might cause an error because of security constraints.
1808
         */
1809
        static {
1810
            String dumpFolder;
1811
            try {
1812
                dumpFolder = doPrivileged(new GetSystemPropertyAction(DUMP_PROPERTY));
1✔
1813
            } catch (RuntimeException exception) {
×
1814
                dumpFolder = null;
×
1815
            }
1✔
1816
            DUMP_FOLDER = dumpFolder;
1✔
1817
        }
1✔
1818

1819
        /**
1820
         * The instrumented type to be created.
1821
         */
1822
        protected final TypeDescription instrumentedType;
1823

1824
        /**
1825
         * The class file specified by the user.
1826
         */
1827
        protected final ClassFileVersion classFileVersion;
1828

1829
        /**
1830
         * The field pool to use.
1831
         */
1832
        protected final FieldPool fieldPool;
1833

1834
        /**
1835
         * The record component pool to use.
1836
         */
1837
        protected final RecordComponentPool recordComponentPool;
1838

1839
        /**
1840
         * The explicit auxiliary types to add to the created type.
1841
         */
1842
        protected final List<? extends DynamicType> auxiliaryTypes;
1843

1844
        /**
1845
         * The instrumented type's declared fields.
1846
         */
1847
        protected final FieldList<FieldDescription.InDefinedShape> fields;
1848

1849
        /**
1850
         * The instrumented type's methods that are declared or inherited.
1851
         */
1852
        protected final MethodList<?> methods;
1853

1854
        /**
1855
         * The instrumented methods relevant to this type creation.
1856
         */
1857
        protected final MethodList<?> instrumentedMethods;
1858

1859
        /**
1860
         * The instrumented type's record components.
1861
         */
1862
        protected final RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents;
1863

1864
        /**
1865
         * The loaded type initializer to apply onto the created type after loading.
1866
         */
1867
        protected final LoadedTypeInitializer loadedTypeInitializer;
1868

1869
        /**
1870
         * The type initializer to include in the created type's type initializer.
1871
         */
1872
        protected final TypeInitializer typeInitializer;
1873

1874
        /**
1875
         * The type attribute appender to apply onto the instrumented type.
1876
         */
1877
        protected final TypeAttributeAppender typeAttributeAppender;
1878

1879
        /**
1880
         * The ASM visitor wrapper to apply onto the class writer.
1881
         */
1882
        protected final AsmVisitorWrapper asmVisitorWrapper;
1883

1884
        /**
1885
         * The annotation value filter factory to apply.
1886
         */
1887
        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
1888

1889
        /**
1890
         * The annotation retention to apply.
1891
         */
1892
        protected final AnnotationRetention annotationRetention;
1893

1894
        /**
1895
         * The naming strategy for auxiliary types to apply.
1896
         */
1897
        protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1898

1899
        /**
1900
         * The implementation context factory to apply.
1901
         */
1902
        protected final Implementation.Context.Factory implementationContextFactory;
1903

1904
        /**
1905
         * Determines if a type should be explicitly validated.
1906
         */
1907
        protected final TypeValidation typeValidation;
1908

1909
        /**
1910
         * The class reader factory to use.
1911
         */
1912
        protected final AsmClassReader.Factory classReaderFactory;
1913

1914
        /**
1915
         * The class writer factory to use.
1916
         */
1917
        protected final AsmClassWriter.Factory classWriterFactory;
1918

1919
        /**
1920
         * The type pool to use for computing stack map frames, if required.
1921
         */
1922
        protected final TypePool typePool;
1923

1924
        /**
1925
         * Creates a new default type writer.
1926
         *
1927
         * @param instrumentedType             The instrumented type to be created.
1928
         * @param classFileVersion             The class file specified by the user.
1929
         * @param fieldPool                    The field pool to use.
1930
         * @param recordComponentPool          The record component pool to use.
1931
         * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
1932
         * @param fields                       The instrumented type's declared fields.
1933
         * @param methods                      The instrumented type's declared and virtually inherited methods.
1934
         * @param instrumentedMethods          The instrumented methods relevant to this type creation.
1935
         * @param recordComponents             The instrumented type's record components.
1936
         * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
1937
         * @param typeInitializer              The type initializer to include in the created type's type initializer.
1938
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
1939
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
1940
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
1941
         * @param annotationRetention          The annotation retention to apply.
1942
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
1943
         * @param implementationContextFactory The implementation context factory to apply.
1944
         * @param typeValidation               Determines if a type should be explicitly validated.
1945
         * @param classReaderFactory           The class reader factory to use.
1946
         * @param classWriterFactory           The class writer factory to use.
1947
         * @param typePool                     The type pool to use for computing stack map frames, if required.
1948
         */
1949
        protected Default(TypeDescription instrumentedType,
1950
                          ClassFileVersion classFileVersion,
1951
                          FieldPool fieldPool,
1952
                          RecordComponentPool recordComponentPool,
1953
                          List<? extends DynamicType> auxiliaryTypes,
1954
                          FieldList<FieldDescription.InDefinedShape> fields,
1955
                          MethodList<?> methods,
1956
                          MethodList<?> instrumentedMethods,
1957
                          RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
1958
                          LoadedTypeInitializer loadedTypeInitializer,
1959
                          TypeInitializer typeInitializer,
1960
                          TypeAttributeAppender typeAttributeAppender,
1961
                          AsmVisitorWrapper asmVisitorWrapper,
1962
                          AnnotationValueFilter.Factory annotationValueFilterFactory,
1963
                          AnnotationRetention annotationRetention,
1964
                          AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1965
                          Implementation.Context.Factory implementationContextFactory,
1966
                          TypeValidation typeValidation,
1967
                          AsmClassReader.Factory classReaderFactory,
1968
                          AsmClassWriter.Factory classWriterFactory,
1969
                          TypePool typePool) {
1✔
1970
            this.instrumentedType = instrumentedType;
1✔
1971
            this.classFileVersion = classFileVersion;
1✔
1972
            this.fieldPool = fieldPool;
1✔
1973
            this.recordComponentPool = recordComponentPool;
1✔
1974
            this.auxiliaryTypes = auxiliaryTypes;
1✔
1975
            this.fields = fields;
1✔
1976
            this.methods = methods;
1✔
1977
            this.instrumentedMethods = instrumentedMethods;
1✔
1978
            this.recordComponents = recordComponents;
1✔
1979
            this.loadedTypeInitializer = loadedTypeInitializer;
1✔
1980
            this.typeInitializer = typeInitializer;
1✔
1981
            this.typeAttributeAppender = typeAttributeAppender;
1✔
1982
            this.asmVisitorWrapper = asmVisitorWrapper;
1✔
1983
            this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
1984
            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
1985
            this.annotationRetention = annotationRetention;
1✔
1986
            this.implementationContextFactory = implementationContextFactory;
1✔
1987
            this.typeValidation = typeValidation;
1✔
1988
            this.classReaderFactory = classReaderFactory;
1✔
1989
            this.classWriterFactory = classWriterFactory;
1✔
1990
            this.typePool = typePool;
1✔
1991
        }
1✔
1992

1993
        /**
1994
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1995
         *
1996
         * @param action The action to execute from a privileged context.
1997
         * @param <T>    The type of the action's resolved value.
1998
         * @return The action's resolved value.
1999
         */
2000
        @AccessControllerPlugin.Enhance
2001
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
2002
            return action.run();
×
2003
        }
2004

2005
        /**
2006
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
2007
         *
2008
         * @param action The action to execute from a privileged context.
2009
         * @param <T>    The type of the action's resolved value.
2010
         * @return The action's resolved value.
2011
         * @throws Exception If an exception occurs.
2012
         */
2013
        @AccessControllerPlugin.Enhance
2014
        private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Exception {
2015
            return action.run();
×
2016
        }
2017

2018
        /**
2019
         * Creates a type writer for creating a new type.
2020
         *
2021
         * @param methodRegistry               The compiled method registry to use.
2022
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2023
         * @param fieldPool                    The field pool to use.
2024
         * @param recordComponentPool          The record component pool to use.
2025
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2026
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2027
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2028
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2029
         * @param annotationRetention          The annotation retention to apply.
2030
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2031
         * @param implementationContextFactory The implementation context factory to apply.
2032
         * @param typeValidation               Determines if a type should be explicitly validated.
2033
         * @param classReaderFactory           The class reader factory to use.
2034
         * @param classWriterFactory           The class writer factory to use.
2035
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2036
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2037
         * @return A suitable type writer.
2038
         */
2039
        public static <U> TypeWriter<U> forCreation(MethodRegistry.Compiled methodRegistry,
2040
                                                    List<? extends DynamicType> auxiliaryTypes,
2041
                                                    FieldPool fieldPool,
2042
                                                    RecordComponentPool recordComponentPool,
2043
                                                    TypeAttributeAppender typeAttributeAppender,
2044
                                                    AsmVisitorWrapper asmVisitorWrapper,
2045
                                                    ClassFileVersion classFileVersion,
2046
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2047
                                                    AnnotationRetention annotationRetention,
2048
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2049
                                                    Implementation.Context.Factory implementationContextFactory,
2050
                                                    TypeValidation typeValidation,
2051
                                                    AsmClassReader.Factory classReaderFactory,
2052
                                                    AsmClassWriter.Factory classWriterFactory,
2053
                                                    TypePool typePool) {
2054
            return new ForCreation<U>(methodRegistry.getInstrumentedType(),
1✔
2055
                    classFileVersion,
2056
                    fieldPool,
2057
                    methodRegistry,
2058
                    recordComponentPool,
2059
                    auxiliaryTypes,
2060
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2061
                    methodRegistry.getMethods(),
1✔
2062
                    methodRegistry.getInstrumentedMethods(),
1✔
2063
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2064
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2065
                    methodRegistry.getTypeInitializer(),
1✔
2066
                    typeAttributeAppender,
2067
                    asmVisitorWrapper,
2068
                    annotationValueFilterFactory,
2069
                    annotationRetention,
2070
                    auxiliaryTypeNamingStrategy,
2071
                    implementationContextFactory,
2072
                    typeValidation,
2073
                    classReaderFactory,
2074
                    classWriterFactory,
2075
                    typePool);
2076
        }
2077

2078
        /**
2079
         * Creates a type writer for redefining a type.
2080
         *
2081
         * @param methodRegistry               The compiled method registry to use.
2082
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2083
         * @param fieldPool                    The field pool to use.
2084
         * @param recordComponentPool          The record component pool to use.
2085
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2086
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2087
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2088
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2089
         * @param annotationRetention          The annotation retention to apply.
2090
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2091
         * @param implementationContextFactory The implementation context factory to apply.
2092
         * @param typeValidation               Determines if a type should be explicitly validated.
2093
         * @param classReaderFactory           The class reader factory to use.
2094
         * @param classWriterFactory           The class writer factory to use.
2095
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2096
         * @param originalType                 The original type that is being redefined or rebased.
2097
         * @param classFileLocator             The class file locator for locating the original type's class file.
2098
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2099
         * @return A suitable type writer.
2100
         */
2101
        public static <U> TypeWriter<U> forRedefinition(MethodRegistry.Prepared methodRegistry,
2102
                                                        List<? extends DynamicType> auxiliaryTypes,
2103
                                                        FieldPool fieldPool,
2104
                                                        RecordComponentPool recordComponentPool,
2105
                                                        TypeAttributeAppender typeAttributeAppender,
2106
                                                        AsmVisitorWrapper asmVisitorWrapper,
2107
                                                        ClassFileVersion classFileVersion,
2108
                                                        AnnotationValueFilter.Factory annotationValueFilterFactory,
2109
                                                        AnnotationRetention annotationRetention,
2110
                                                        AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2111
                                                        Implementation.Context.Factory implementationContextFactory,
2112
                                                        TypeValidation typeValidation,
2113
                                                        AsmClassReader.Factory classReaderFactory,
2114
                                                        AsmClassWriter.Factory classWriterFactory,
2115
                                                        TypePool typePool,
2116
                                                        TypeDescription originalType,
2117
                                                        ClassFileLocator classFileLocator) {
2118
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2119
                    classFileVersion,
2120
                    fieldPool,
2121
                    recordComponentPool,
2122
                    auxiliaryTypes,
2123
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2124
                    methodRegistry.getMethods(),
1✔
2125
                    methodRegistry.getInstrumentedMethods(),
1✔
2126
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2127
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2128
                    methodRegistry.getTypeInitializer(),
1✔
2129
                    typeAttributeAppender,
2130
                    asmVisitorWrapper,
2131
                    annotationValueFilterFactory,
2132
                    annotationRetention,
2133
                    auxiliaryTypeNamingStrategy,
2134
                    implementationContextFactory,
2135
                    typeValidation,
2136
                    classReaderFactory,
2137
                    classWriterFactory,
2138
                    typePool,
2139
                    originalType,
2140
                    classFileLocator,
2141
                    methodRegistry,
2142
                    SubclassImplementationTarget.Factory.LEVEL_TYPE,
2143
                    MethodRebaseResolver.Disabled.INSTANCE);
2144
        }
2145

2146
        /**
2147
         * Creates a type writer for rebasing a type.
2148
         *
2149
         * @param methodRegistry               The compiled method registry to use.
2150
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2151
         * @param fieldPool                    The field pool to use.
2152
         * @param recordComponentPool          The record component pool to use.
2153
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2154
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2155
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2156
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2157
         * @param annotationRetention          The annotation retention to apply.
2158
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2159
         * @param implementationContextFactory The implementation context factory to apply.
2160
         * @param typeValidation               Determines if a type should be explicitly validated.
2161
         * @param classReaderFactory           The class reader factory to use.
2162
         * @param classWriterFactory           The class writer factory to use.
2163
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2164
         * @param originalType                 The original type that is being redefined or rebased.
2165
         * @param classFileLocator             The class file locator for locating the original type's class file.
2166
         * @param methodRebaseResolver         The method rebase resolver to use for rebasing names.
2167
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2168
         * @return A suitable type writer.
2169
         */
2170
        public static <U> TypeWriter<U> forRebasing(MethodRegistry.Prepared methodRegistry,
2171
                                                    List<? extends DynamicType> auxiliaryTypes,
2172
                                                    FieldPool fieldPool,
2173
                                                    RecordComponentPool recordComponentPool,
2174
                                                    TypeAttributeAppender typeAttributeAppender,
2175
                                                    AsmVisitorWrapper asmVisitorWrapper,
2176
                                                    ClassFileVersion classFileVersion,
2177
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2178
                                                    AnnotationRetention annotationRetention,
2179
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2180
                                                    Implementation.Context.Factory implementationContextFactory,
2181
                                                    TypeValidation typeValidation,
2182
                                                    AsmClassReader.Factory classReaderFactory,
2183
                                                    AsmClassWriter.Factory classWriterFactory,
2184
                                                    TypePool typePool,
2185
                                                    TypeDescription originalType,
2186
                                                    ClassFileLocator classFileLocator,
2187
                                                    MethodRebaseResolver methodRebaseResolver) {
2188
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2189
                    classFileVersion,
2190
                    fieldPool,
2191
                    recordComponentPool,
2192
                    CompoundList.of(auxiliaryTypes, methodRebaseResolver.getAuxiliaryTypes()),
1✔
2193
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2194
                    methodRegistry.getMethods(),
1✔
2195
                    methodRegistry.getInstrumentedMethods(),
1✔
2196
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2197
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2198
                    methodRegistry.getTypeInitializer(),
1✔
2199
                    typeAttributeAppender,
2200
                    asmVisitorWrapper,
2201
                    annotationValueFilterFactory,
2202
                    annotationRetention,
2203
                    auxiliaryTypeNamingStrategy,
2204
                    implementationContextFactory,
2205
                    typeValidation,
2206
                    classReaderFactory,
2207
                    classWriterFactory,
2208
                    typePool,
2209
                    originalType,
2210
                    classFileLocator,
2211
                    methodRegistry,
2212
                    new RebaseImplementationTarget.Factory(methodRebaseResolver),
2213
                    methodRebaseResolver);
2214
        }
2215

2216
        /**
2217
         * Creates a type writer for decorating a type.
2218
         *
2219
         * @param instrumentedType             The instrumented type.
2220
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2221
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2222
         * @param methods                      The methods to instrument.
2223
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2224
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2225
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2226
         * @param annotationRetention          The annotation retention to apply.
2227
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2228
         * @param implementationContextFactory The implementation context factory to apply.
2229
         * @param typeValidation               Determines if a type should be explicitly validated.
2230
         * @param classReaderFactory           The class reader factory to use.
2231
         * @param classWriterFactory           The class writer factory to use.
2232
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2233
         * @param classFileLocator             The class file locator for locating the original type's class file.
2234
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2235
         * @return A suitable type writer.
2236
         */
2237
        public static <U> TypeWriter<U> forDecoration(TypeDescription instrumentedType,
2238
                                                      ClassFileVersion classFileVersion,
2239
                                                      List<? extends DynamicType> auxiliaryTypes,
2240
                                                      List<? extends MethodDescription> methods,
2241
                                                      TypeAttributeAppender typeAttributeAppender,
2242
                                                      AsmVisitorWrapper asmVisitorWrapper,
2243
                                                      AnnotationValueFilter.Factory annotationValueFilterFactory,
2244
                                                      AnnotationRetention annotationRetention,
2245
                                                      AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2246
                                                      Implementation.Context.Factory implementationContextFactory,
2247
                                                      TypeValidation typeValidation,
2248
                                                      AsmClassReader.Factory classReaderFactory,
2249
                                                      AsmClassWriter.Factory classWriterFactory,
2250
                                                      TypePool typePool,
2251
                                                      ClassFileLocator classFileLocator) {
2252
            return new ForInlining.WithDecorationOnly<U>(instrumentedType,
1✔
2253
                    classFileVersion,
2254
                    auxiliaryTypes,
2255
                    new MethodList.Explicit<MethodDescription>(methods),
2256
                    typeAttributeAppender,
2257
                    asmVisitorWrapper,
2258
                    annotationValueFilterFactory,
2259
                    annotationRetention,
2260
                    auxiliaryTypeNamingStrategy,
2261
                    implementationContextFactory,
2262
                    typeValidation,
2263
                    classReaderFactory,
2264
                    classWriterFactory,
2265
                    typePool,
2266
                    classFileLocator);
2267
        }
2268

2269
        /**
2270
         * {@inheritDoc}
2271
         */
2272
        @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Setting a debugging property should never change the program outcome.")
2273
        public DynamicType.Unloaded<S> make(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2274
            ClassDumpAction.Dispatcher dispatcher = DUMP_FOLDER == null
1✔
2275
                    ? ClassDumpAction.Dispatcher.Disabled.INSTANCE
2276
                    : new ClassDumpAction.Dispatcher.Enabled(DUMP_FOLDER, System.currentTimeMillis());
1✔
2277
            UnresolvedType unresolvedType = create(typeResolutionStrategy.injectedInto(typeInitializer), dispatcher);
1✔
2278
            dispatcher.dump(instrumentedType, false, unresolvedType.getBinaryRepresentation());
1✔
2279
            return unresolvedType.toDynamicType(typeResolutionStrategy);
1✔
2280
        }
2281

2282
        /**
2283
         * Creates an unresolved version of the dynamic type.
2284
         *
2285
         * @param typeInitializer The type initializer to use.
2286
         * @param dispatcher      A dispatcher for dumping class files.
2287
         * @return An unresolved type.
2288
         */
2289
        protected abstract UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher);
2290

2291
        /**
2292
         * An unresolved type.
2293
         */
2294
        @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2295
        protected class UnresolvedType {
2296

2297
            /**
2298
             * The type's binary representation.
2299
             */
2300
            private final byte[] binaryRepresentation;
2301

2302
            /**
2303
             * A list of auxiliary types for this unresolved type.
2304
             */
2305
            private final List<? extends DynamicType> auxiliaryTypes;
2306

2307
            /**
2308
             * Creates a new unresolved type.
2309
             *
2310
             * @param binaryRepresentation The type's binary representation.
2311
             * @param auxiliaryTypes       A list of auxiliary types for this unresolved type.
2312
             */
2313
            protected UnresolvedType(byte[] binaryRepresentation, List<? extends DynamicType> auxiliaryTypes) {
1✔
2314
                this.binaryRepresentation = binaryRepresentation;
1✔
2315
                this.auxiliaryTypes = auxiliaryTypes;
1✔
2316
            }
1✔
2317

2318
            /**
2319
             * Resolves this type to a dynamic type.
2320
             *
2321
             * @param typeResolutionStrategy The type resolution strategy to apply.
2322
             * @return A dynamic type representing the inlined type.
2323
             */
2324
            protected DynamicType.Unloaded<S> toDynamicType(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2325
                return new DynamicType.Default.Unloaded<S>(instrumentedType,
1✔
2326
                        binaryRepresentation,
2327
                        loadedTypeInitializer,
2328
                        CompoundList.of(Default.this.auxiliaryTypes, auxiliaryTypes),
1✔
2329
                        typeResolutionStrategy);
2330
            }
2331

2332
            /**
2333
             * Returns the binary representation of this unresolved type.
2334
             *
2335
             * @return The binary representation of this unresolved type.
2336
             */
2337
            protected byte[] getBinaryRepresentation() {
2338
                return binaryRepresentation;
1✔
2339
            }
2340
        }
2341

2342
        /**
2343
         * A key to represent a unique signature.
2344
         */
2345
        protected static class SignatureKey {
2346

2347
            /**
2348
             * The represented internal name.
2349
             */
2350
            private final String internalName;
2351

2352
            /**
2353
             * The represented descriptor.
2354
             */
2355
            private final String descriptor;
2356

2357
            /**
2358
             * Creates a new signature key.
2359
             *
2360
             * @param internalName The represented internal name.
2361
             * @param descriptor   The represented descriptor.
2362
             */
2363
            public SignatureKey(String internalName, String descriptor) {
1✔
2364
                this.internalName = internalName;
1✔
2365
                this.descriptor = descriptor;
1✔
2366
            }
1✔
2367

2368
            @Override
2369
            public boolean equals(@MaybeNull Object other) {
2370
                if (this == other) return true;
1✔
2371
                if (other == null || getClass() != other.getClass()) return false;
1✔
2372
                SignatureKey that = (SignatureKey) other;
1✔
2373
                return internalName.equals(that.internalName) && descriptor.equals(that.descriptor);
1✔
2374
            }
2375

2376
            @Override
2377
            public int hashCode() {
2378
                return 17 + internalName.hashCode() + 31 * descriptor.hashCode();
1✔
2379
            }
2380
        }
2381

2382
        /**
2383
         * A class validator that validates that a class only defines members that are appropriate for the sort of the generated class.
2384
         */
2385
        protected static class ValidatingClassVisitor extends ClassVisitor {
2386

2387
            /**
2388
             * Indicates that a method has no method parameters.
2389
             */
2390
            private static final String NO_PARAMETERS = "()";
2391

2392
            /**
2393
             * Indicates that a method returns void.
2394
             */
2395
            private static final String RETURNS_VOID = "V";
2396

2397
            /**
2398
             * The descriptor of the {@link String} type.
2399
             */
2400
            private static final String STRING_DESCRIPTOR = "Ljava/lang/String;";
2401

2402
            /**
2403
             * Indicates that a field is ignored.
2404
             */
2405
            @AlwaysNull
2406
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
2407

2408
            /**
2409
             * Indicates that a method is ignored.
2410
             */
2411
            @AlwaysNull
2412
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
2413

2414
            /**
2415
             * The constraint to assert the members against. The constraint is first defined when the general class information is visited.
2416
             */
2417
            @UnknownNull
2418
            private Constraint constraint;
2419

2420
            /**
2421
             * Creates a validating class visitor.
2422
             *
2423
             * @param classVisitor The class visitor to which any calls are delegated to.
2424
             */
2425
            protected ValidatingClassVisitor(ClassVisitor classVisitor) {
2426
                super(OpenedClassReader.ASM_API, classVisitor);
1✔
2427
            }
1✔
2428

2429
            /**
2430
             * Adds a validating visitor if type validation is enabled.
2431
             *
2432
             * @param classVisitor   The original class visitor.
2433
             * @param typeValidation The type validation state.
2434
             * @return A class visitor that applies type validation if this is required.
2435
             */
2436
            protected static ClassVisitor of(ClassVisitor classVisitor, TypeValidation typeValidation) {
2437
                return typeValidation.isEnabled()
1✔
2438
                        ? new ValidatingClassVisitor(classVisitor)
2439
                        : classVisitor;
2440
            }
2441

2442
            @Override
2443
            public void visit(int version, int modifiers, String name, @MaybeNull String signature, @MaybeNull String superName, @MaybeNull String[] interfaceInternalName) {
2444
                ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(version);
1✔
2445
                List<Constraint> constraints = new ArrayList<Constraint>();
1✔
2446
                constraints.add(new Constraint.ForClassFileVersion(classFileVersion));
1✔
2447
                if (name.endsWith('/' + PackageDescription.PACKAGE_CLASS_NAME)) {
1✔
2448
                    constraints.add(Constraint.ForPackageType.INSTANCE);
1✔
2449
                } else if ((modifiers & Opcodes.ACC_ANNOTATION) != 0) {
1✔
2450
                    if (!classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
2451
                        throw new IllegalStateException("Cannot define an annotation type for class file version " + classFileVersion);
1✔
2452
                    }
2453
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2454
                            ? Constraint.ForAnnotation.JAVA_8
2455
                            : Constraint.ForAnnotation.CLASSIC);
2456
                } else if ((modifiers & Opcodes.ACC_INTERFACE) != 0) {
1✔
2457
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2458
                            ? Constraint.ForInterface.JAVA_8
2459
                            : Constraint.ForInterface.CLASSIC);
2460
                } else if ((modifiers & Opcodes.ACC_ABSTRACT) != 0) {
1✔
2461
                    constraints.add(Constraint.ForClass.ABSTRACT);
1✔
2462
                } else {
2463
                    constraints.add(Constraint.ForClass.MANIFEST);
1✔
2464
                }
2465
                boolean record;
2466
                if ((modifiers & Opcodes.ACC_RECORD) != 0) {
1✔
2467
                    constraints.add(Constraint.ForRecord.INSTANCE);
1✔
2468
                    record = true;
1✔
2469
                } else {
2470
                    record = false;
1✔
2471
                }
2472
                constraint = new Constraint.Compound(constraints);
1✔
2473
                constraint.assertType(modifiers, interfaceInternalName != null, signature != null);
1✔
2474
                if (record) {
1✔
2475
                    constraint.assertRecord();
×
2476
                }
2477
                super.visit(version, modifiers, name, signature, superName, interfaceInternalName);
1✔
2478
            }
1✔
2479

2480
            @Override
2481
            public void visitPermittedSubclass(String permittedSubclass) {
2482
                constraint.assertPermittedSubclass();
×
2483
                super.visitPermittedSubclass(permittedSubclass);
×
2484
            }
×
2485

2486
            @Override
2487
            @MaybeNull
2488
            public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
2489
                constraint.assertAnnotation();
1✔
2490
                return super.visitAnnotation(descriptor, visible);
1✔
2491
            }
2492

2493
            @Override
2494
            @MaybeNull
2495
            public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
2496
                constraint.assertTypeAnnotation();
1✔
2497
                return super.visitTypeAnnotation(typeReference, typePath, descriptor, visible);
1✔
2498
            }
2499

2500
            @Override
2501
            public void visitNestHost(String nestHost) {
2502
                constraint.assertNestMate();
×
2503
                super.visitNestHost(nestHost);
×
2504
            }
×
2505

2506
            @Override
2507
            public void visitNestMember(String nestMember) {
2508
                constraint.assertNestMate();
×
2509
                super.visitNestMember(nestMember);
×
2510
            }
×
2511

2512
            @Override
2513
            @MaybeNull
2514
            public FieldVisitor visitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
2515
                if (value != null) {
1✔
2516
                    Class<?> type;
2517
                    switch (descriptor.charAt(0)) {
1✔
2518
                        case 'Z':
2519
                        case 'B':
2520
                        case 'C':
2521
                        case 'S':
2522
                        case 'I':
2523
                            type = Integer.class;
1✔
2524
                            break;
1✔
2525
                        case 'J':
2526
                            type = Long.class;
1✔
2527
                            break;
1✔
2528
                        case 'F':
2529
                            type = Float.class;
1✔
2530
                            break;
1✔
2531
                        case 'D':
2532
                            type = Double.class;
1✔
2533
                            break;
1✔
2534
                        default:
2535
                            if (!descriptor.equals(STRING_DESCRIPTOR)) {
1✔
2536
                                throw new IllegalStateException("Cannot define a default value for type of field " + name);
1✔
2537
                            }
2538
                            type = String.class;
1✔
2539
                    }
2540
                    if (!type.isInstance(value)) {
1✔
2541
                        throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value + " (" + value.getClass().getName() + ")");
1✔
2542
                    } else if (type == Integer.class) {
1✔
2543
                        boolean outOfRange;
2544
                        switch (descriptor.charAt(0)) {
1✔
2545
                            case 'Z':
2546
                                outOfRange = (Integer) value < 0 || (Integer) value > 1;
1✔
2547
                                break;
1✔
2548
                            case 'B':
2549
                                outOfRange = (Integer) value < Byte.MIN_VALUE || (Integer) value > Byte.MAX_VALUE;
1✔
2550
                                break;
1✔
2551
                            case 'S':
2552
                                outOfRange = (Integer) value < Short.MIN_VALUE || (Integer) value > Short.MAX_VALUE;
1✔
2553
                                break;
1✔
2554
                            case 'C':
2555
                                outOfRange = (Integer) value < Character.MIN_VALUE || (Integer) value > Character.MAX_VALUE;
1✔
2556
                                break;
1✔
2557
                            default:
2558
                                outOfRange = false;
1✔
2559
                        }
2560
                        if (outOfRange) {
1✔
2561
                            throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value);
1✔
2562
                        }
2563
                    }
2564
                }
2565
                constraint.assertField(name,
1✔
2566
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2567
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2568
                        (modifiers & Opcodes.ACC_FINAL) != 0,
2569
                        signature != null);
2570
                FieldVisitor fieldVisitor = super.visitField(modifiers, name, descriptor, signature, value);
1✔
2571
                return fieldVisitor == null
1✔
2572
                        ? IGNORE_FIELD
2573
                        : new ValidatingFieldVisitor(fieldVisitor);
2574
            }
2575

2576
            @Override
2577
            @MaybeNull
2578
            public MethodVisitor visitMethod(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull String[] exceptionInternalName) {
2579
                constraint.assertMethod(name,
1✔
2580
                        (modifiers & Opcodes.ACC_ABSTRACT) != 0,
2581
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2582
                        (modifiers & Opcodes.ACC_PRIVATE) != 0,
2583
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2584
                        !name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)
1✔
2585
                                && !name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)
1✔
2586
                                && (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) == 0,
2587
                        name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME),
1✔
2588
                        !descriptor.startsWith(NO_PARAMETERS) || descriptor.endsWith(RETURNS_VOID),
1✔
2589
                        signature != null);
2590
                MethodVisitor methodVisitor = super.visitMethod(modifiers, name, descriptor, signature, exceptionInternalName);
1✔
2591
                return methodVisitor == null
1✔
2592
                        ? IGNORE_METHOD
2593
                        : new ValidatingMethodVisitor(methodVisitor, name);
2594
            }
2595

2596
            /**
2597
             * A constraint for members that are legal for a given type.
2598
             */
2599
            protected interface Constraint {
2600

2601
                /**
2602
                 * Asserts if the type can legally represent a package description.
2603
                 *
2604
                 * @param modifier          The modifier that is to be written to the type.
2605
                 * @param definesInterfaces {@code true} if this type implements at least one interface.
2606
                 * @param isGeneric         {@code true} if this type defines a generic type signature.
2607
                 */
2608
                void assertType(int modifier, boolean definesInterfaces, boolean isGeneric);
2609

2610
                /**
2611
                 * Asserts a field for being valid.
2612
                 *
2613
                 * @param name      The name of the field.
2614
                 * @param isPublic  {@code true} if this field is public.
2615
                 * @param isStatic  {@code true} if this field is static.
2616
                 * @param isFinal   {@code true} if this field is final.
2617
                 * @param isGeneric {@code true} if this field defines a generic signature.
2618
                 */
2619
                void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric);
2620

2621
                /**
2622
                 * Asserts a method for being valid.
2623
                 *
2624
                 * @param name                       The name of the method.
2625
                 * @param isAbstract                 {@code true} if the method is abstract.
2626
                 * @param isPublic                   {@code true} if this method is public.
2627
                 * @param isPrivate                  {@code true} if this method is private.
2628
                 * @param isStatic                   {@code true} if this method is static.
2629
                 * @param isVirtual                  {@code true} if this method is virtual.
2630
                 * @param isConstructor              {@code true} if this method is a constructor.
2631
                 * @param isDefaultValueIncompatible {@code true} if a method's signature cannot describe an annotation property method.
2632
                 * @param isGeneric                  {@code true} if this method defines a generic signature.
2633
                 */
2634
                void assertMethod(String name,
2635
                                  boolean isAbstract,
2636
                                  boolean isPublic,
2637
                                  boolean isPrivate,
2638
                                  boolean isStatic,
2639
                                  boolean isVirtual,
2640
                                  boolean isConstructor,
2641
                                  boolean isDefaultValueIncompatible,
2642
                                  boolean isGeneric);
2643

2644
                /**
2645
                 * Asserts the legitimacy of an annotation for the instrumented type.
2646
                 */
2647
                void assertAnnotation();
2648

2649
                /**
2650
                 * Asserts the legitimacy of a type annotation for the instrumented type.
2651
                 */
2652
                void assertTypeAnnotation();
2653

2654
                /**
2655
                 * Asserts if a default value is legal for a method.
2656
                 *
2657
                 * @param name The name of the method.
2658
                 */
2659
                void assertDefaultValue(String name);
2660

2661
                /**
2662
                 * Asserts if it is legal to invoke a default method from a type.
2663
                 */
2664
                void assertDefaultMethodCall();
2665

2666
                /**
2667
                 * Asserts the capability to store a type constant in the class's constant pool.
2668
                 */
2669
                void assertTypeInConstantPool();
2670

2671
                /**
2672
                 * Asserts the capability to store a method type constant in the class's constant pool.
2673
                 */
2674
                void assertMethodTypeInConstantPool();
2675

2676
                /**
2677
                 * Asserts the capability to store a method handle in the class's constant pool.
2678
                 */
2679
                void assertHandleInConstantPool();
2680

2681
                /**
2682
                 * Asserts the capability to invoke a method dynamically.
2683
                 */
2684
                void assertInvokeDynamic();
2685

2686
                /**
2687
                 * Asserts the capability of executing a subroutine.
2688
                 */
2689
                void assertSubRoutine();
2690

2691
                /**
2692
                 * Asserts the capability of storing a dynamic value in the constant pool.
2693
                 */
2694
                void assertDynamicValueInConstantPool();
2695

2696
                /**
2697
                 * Asserts the capability of storing nest mate information.
2698
                 */
2699
                void assertNestMate();
2700

2701
                /**
2702
                 * Asserts the presence of a record component.
2703
                 */
2704
                void assertRecord();
2705

2706
                /**
2707
                 * Asserts the presence of a permitted subclass.
2708
                 */
2709
                void assertPermittedSubclass();
2710

2711
                /**
2712
                 * Represents the constraint of a class type.
2713
                 */
2714
                enum ForClass implements Constraint {
1✔
2715

2716
                    /**
2717
                     * Represents the constraints of a non-abstract class.
2718
                     */
2719
                    MANIFEST(true),
1✔
2720

2721
                    /**
2722
                     * Represents the constraints of an abstract class.
2723
                     */
2724
                    ABSTRACT(false);
1✔
2725

2726
                    /**
2727
                     * {@code true} if this instance represents the constraints a non-abstract class.
2728
                     */
2729
                    private final boolean manifestType;
2730

2731
                    /**
2732
                     * Creates a new constraint for a class.
2733
                     *
2734
                     * @param manifestType {@code true} if this instance represents a non-abstract class.
2735
                     */
2736
                    ForClass(boolean manifestType) {
1✔
2737
                        this.manifestType = manifestType;
1✔
2738
                    }
1✔
2739

2740
                    /**
2741
                     * {@inheritDoc}
2742
                     */
2743
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2744
                        /* do nothing */
2745
                    }
1✔
2746

2747
                    /**
2748
                     * {@inheritDoc}
2749
                     */
2750
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2751
                        /* do nothing */
2752
                    }
1✔
2753

2754
                    /**
2755
                     * {@inheritDoc}
2756
                     */
2757
                    public void assertMethod(String name,
2758
                                             boolean isAbstract,
2759
                                             boolean isPublic,
2760
                                             boolean isPrivate,
2761
                                             boolean isStatic,
2762
                                             boolean isVirtual,
2763
                                             boolean isConstructor,
2764
                                             boolean isDefaultValueIncompatible,
2765
                                             boolean isGeneric) {
2766
                        if (isAbstract && manifestType) {
1✔
2767
                            throw new IllegalStateException("Cannot define abstract method '" + name + "' for non-abstract class");
1✔
2768
                        }
2769
                    }
1✔
2770

2771
                    /**
2772
                     * {@inheritDoc}
2773
                     */
2774
                    public void assertAnnotation() {
2775
                        /* do nothing */
2776
                    }
1✔
2777

2778
                    /**
2779
                     * {@inheritDoc}
2780
                     */
2781
                    public void assertTypeAnnotation() {
2782
                        /* do nothing */
2783
                    }
1✔
2784

2785
                    /**
2786
                     * {@inheritDoc}
2787
                     */
2788
                    public void assertDefaultValue(String name) {
2789
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
1✔
2790
                    }
2791

2792
                    /**
2793
                     * {@inheritDoc}
2794
                     */
2795
                    public void assertDefaultMethodCall() {
2796
                        /* do nothing */
2797
                    }
1✔
2798

2799
                    /**
2800
                     * {@inheritDoc}
2801
                     */
2802
                    public void assertTypeInConstantPool() {
2803
                        /* do nothing */
2804
                    }
1✔
2805

2806
                    /**
2807
                     * {@inheritDoc}
2808
                     */
2809
                    public void assertMethodTypeInConstantPool() {
2810
                        /* do nothing */
2811
                    }
1✔
2812

2813
                    /**
2814
                     * {@inheritDoc}
2815
                     */
2816
                    public void assertHandleInConstantPool() {
2817
                        /* do nothing */
2818
                    }
1✔
2819

2820
                    /**
2821
                     * {@inheritDoc}
2822
                     */
2823
                    public void assertInvokeDynamic() {
2824
                        /* do nothing */
2825
                    }
1✔
2826

2827
                    /**
2828
                     * {@inheritDoc}
2829
                     */
2830
                    public void assertSubRoutine() {
2831
                        /* do nothing */
2832
                    }
1✔
2833

2834
                    /**
2835
                     * {@inheritDoc}
2836
                     */
2837
                    public void assertDynamicValueInConstantPool() {
2838
                        /* do nothing */
2839
                    }
×
2840

2841
                    /**
2842
                     * {@inheritDoc}
2843
                     */
2844
                    public void assertNestMate() {
2845
                        /* do nothing */
2846
                    }
×
2847

2848
                    /**
2849
                     * {@inheritDoc}
2850
                     */
2851
                    public void assertRecord() {
2852
                        /* do nothing */
2853
                    }
×
2854

2855
                    /**
2856
                     * {@inheritDoc}
2857
                     */
2858
                    public void assertPermittedSubclass() {
2859
                        /* do nothing */
2860
                    }
×
2861
                }
2862

2863
                /**
2864
                 * Represents the constraint of a package type.
2865
                 */
2866
                enum ForPackageType implements Constraint {
1✔
2867

2868
                    /**
2869
                     * The singleton instance.
2870
                     */
2871
                    INSTANCE;
1✔
2872

2873
                    /**
2874
                     * {@inheritDoc}
2875
                     */
2876
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2877
                        throw new IllegalStateException("Cannot define a field for a package description type");
1✔
2878
                    }
2879

2880
                    /**
2881
                     * {@inheritDoc}
2882
                     */
2883
                    public void assertMethod(String name,
2884
                                             boolean isAbstract,
2885
                                             boolean isPublic,
2886
                                             boolean isPrivate,
2887
                                             boolean isStatic,
2888
                                             boolean isVirtual,
2889
                                             boolean isConstructor,
2890
                                             boolean isNoDefaultValue,
2891
                                             boolean isGeneric) {
2892
                        throw new IllegalStateException("Cannot define a method for a package description type");
×
2893
                    }
2894

2895
                    /**
2896
                     * {@inheritDoc}
2897
                     */
2898
                    public void assertAnnotation() {
2899
                        /* do nothing */
2900
                    }
1✔
2901

2902
                    /**
2903
                     * {@inheritDoc}
2904
                     */
2905
                    public void assertTypeAnnotation() {
2906
                        /* do nothing */
2907
                    }
×
2908

2909
                    /**
2910
                     * {@inheritDoc}
2911
                     */
2912
                    public void assertDefaultValue(String name) {
2913
                        /* do nothing, implicit by forbidding methods */
2914
                    }
×
2915

2916
                    /**
2917
                     * {@inheritDoc}
2918
                     */
2919
                    public void assertDefaultMethodCall() {
2920
                        /* do nothing */
2921
                    }
×
2922

2923
                    /**
2924
                     * {@inheritDoc}
2925
                     */
2926
                    public void assertTypeInConstantPool() {
2927
                        /* do nothing */
2928
                    }
×
2929

2930
                    /**
2931
                     * {@inheritDoc}
2932
                     */
2933
                    public void assertMethodTypeInConstantPool() {
2934
                        /* do nothing */
2935
                    }
×
2936

2937
                    /**
2938
                     * {@inheritDoc}
2939
                     */
2940
                    public void assertHandleInConstantPool() {
2941
                        /* do nothing */
2942
                    }
×
2943

2944
                    /**
2945
                     * {@inheritDoc}
2946
                     */
2947
                    public void assertInvokeDynamic() {
2948
                        /* do nothing */
2949
                    }
×
2950

2951
                    /**
2952
                     * {@inheritDoc}
2953
                     */
2954
                    public void assertSubRoutine() {
2955
                        /* do nothing */
2956
                    }
×
2957

2958
                    /**
2959
                     * {@inheritDoc}
2960
                     */
2961
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2962
                        if (modifier != PackageDescription.PACKAGE_MODIFIERS) {
1✔
2963
                            throw new IllegalStateException("A package description type must define " + PackageDescription.PACKAGE_MODIFIERS + " as modifier");
×
2964
                        } else if (definesInterfaces) {
1✔
2965
                            throw new IllegalStateException("Cannot implement interface for package type");
1✔
2966
                        }
2967
                    }
1✔
2968

2969
                    /**
2970
                     * {@inheritDoc}
2971
                     */
2972
                    public void assertDynamicValueInConstantPool() {
2973
                        /* do nothing */
2974
                    }
×
2975

2976
                    /**
2977
                     * {@inheritDoc}
2978
                     */
2979
                    public void assertNestMate() {
2980
                        /* do nothing */
2981
                    }
×
2982

2983
                    /**
2984
                     * {@inheritDoc}
2985
                     */
2986
                    public void assertRecord() {
2987
                        /* do nothing */
2988
                    }
×
2989

2990
                    /**
2991
                     * {@inheritDoc}
2992
                     */
2993
                    public void assertPermittedSubclass() {
2994
                        /* do nothing */
2995
                    }
×
2996
                }
2997

2998
                /**
2999
                 * Represents the constraint of an interface type.
3000
                 */
3001
                enum ForInterface implements Constraint {
1✔
3002

3003
                    /**
3004
                     * An interface type with the constraints for the Java versions 5 to 7.
3005
                     */
3006
                    CLASSIC(true),
1✔
3007

3008
                    /**
3009
                     * An interface type with the constraints for the Java versions 8+.
3010
                     */
3011
                    JAVA_8(false);
1✔
3012

3013
                    /**
3014
                     * {@code true} if this instance represents a classic interface type (pre Java 8).
3015
                     */
3016
                    private final boolean classic;
3017

3018
                    /**
3019
                     * Creates a constraint for an interface type.
3020
                     *
3021
                     * @param classic {@code true} if this instance represents a classic interface (pre Java 8).
3022
                     */
3023
                    ForInterface(boolean classic) {
1✔
3024
                        this.classic = classic;
1✔
3025
                    }
1✔
3026

3027
                    /**
3028
                     * {@inheritDoc}
3029
                     */
3030
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3031
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3032
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3033
                        }
3034
                    }
1✔
3035

3036
                    /**
3037
                     * {@inheritDoc}
3038
                     */
3039
                    public void assertMethod(String name,
3040
                                             boolean isAbstract,
3041
                                             boolean isPublic,
3042
                                             boolean isPrivate,
3043
                                             boolean isStatic,
3044
                                             boolean isVirtual,
3045
                                             boolean isConstructor,
3046
                                             boolean isDefaultValueIncompatible,
3047
                                             boolean isGeneric) {
3048
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3049
                            if (isConstructor) {
1✔
3050
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3051
                            } else if (classic && !isPublic) {
1✔
3052
                                throw new IllegalStateException("Cannot define non-public method '" + name + "' for interface type");
×
3053
                            } else if (classic && !isVirtual) {
1✔
3054
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 interface type");
×
3055
                            } else if (classic && !isAbstract) {
1✔
3056
                                throw new IllegalStateException("Cannot define default method '" + name + "' for pre-Java 8 interface type");
×
3057
                            }
3058
                        }
3059
                    }
1✔
3060

3061
                    /**
3062
                     * {@inheritDoc}
3063
                     */
3064
                    public void assertAnnotation() {
3065
                        /* do nothing */
3066
                    }
1✔
3067

3068
                    /**
3069
                     * {@inheritDoc}
3070
                     */
3071
                    public void assertTypeAnnotation() {
3072
                        /* do nothing */
3073
                    }
×
3074

3075
                    /**
3076
                     * {@inheritDoc}
3077
                     */
3078
                    public void assertDefaultValue(String name) {
3079
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
×
3080
                    }
3081

3082
                    /**
3083
                     * {@inheritDoc}
3084
                     */
3085
                    public void assertDefaultMethodCall() {
3086
                        /* do nothing */
3087
                    }
1✔
3088

3089
                    /**
3090
                     * {@inheritDoc}
3091
                     */
3092
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3093
                        /* do nothing */
3094
                    }
1✔
3095

3096
                    /**
3097
                     * {@inheritDoc}
3098
                     */
3099
                    public void assertTypeInConstantPool() {
3100
                        /* do nothing */
3101
                    }
×
3102

3103
                    /**
3104
                     * {@inheritDoc}
3105
                     */
3106
                    public void assertMethodTypeInConstantPool() {
3107
                        /* do nothing */
3108
                    }
×
3109

3110
                    /**
3111
                     * {@inheritDoc}
3112
                     */
3113
                    public void assertHandleInConstantPool() {
3114
                        /* do nothing */
3115
                    }
×
3116

3117
                    /**
3118
                     * {@inheritDoc}
3119
                     */
3120
                    public void assertInvokeDynamic() {
3121
                        /* do nothing */
3122
                    }
×
3123

3124
                    /**
3125
                     * {@inheritDoc}
3126
                     */
3127
                    public void assertSubRoutine() {
3128
                        /* do nothing */
3129
                    }
×
3130

3131
                    /**
3132
                     * {@inheritDoc}
3133
                     */
3134
                    public void assertDynamicValueInConstantPool() {
3135
                        /* do nothing */
3136
                    }
×
3137

3138
                    /**
3139
                     * {@inheritDoc}
3140
                     */
3141
                    public void assertNestMate() {
3142
                        /* do nothing */
3143
                    }
×
3144

3145
                    /**
3146
                     * {@inheritDoc}
3147
                     */
3148
                    public void assertRecord() {
3149
                        /* do nothing */
3150
                    }
×
3151

3152
                    /**
3153
                     * {@inheritDoc}
3154
                     */
3155
                    public void assertPermittedSubclass() {
3156
                        /* do nothing */
3157
                    }
×
3158
                }
3159

3160
                /**
3161
                 * Represents the constraint of a record type.
3162
                 */
3163
                enum ForRecord implements Constraint {
1✔
3164

3165
                    /**
3166
                     * The singleton instance.
3167
                     */
3168
                    INSTANCE;
1✔
3169

3170
                    /**
3171
                     * {@inheritDoc}
3172
                     */
3173
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3174
                        /* do nothing */
3175
                    }
×
3176

3177
                    /**
3178
                     * {@inheritDoc}
3179
                     */
3180
                    public void assertMethod(String name,
3181
                                             boolean isAbstract,
3182
                                             boolean isPublic,
3183
                                             boolean isPrivate,
3184
                                             boolean isStatic,
3185
                                             boolean isVirtual,
3186
                                             boolean isConstructor,
3187
                                             boolean isDefaultValueIncompatible,
3188
                                             boolean isGeneric) {
3189
                        /* do nothing */
3190
                    }
×
3191

3192
                    /**
3193
                     * {@inheritDoc}
3194
                     */
3195
                    public void assertAnnotation() {
3196
                        /* do nothing */
3197
                    }
×
3198

3199
                    /**
3200
                     * {@inheritDoc}
3201
                     */
3202
                    public void assertTypeAnnotation() {
3203
                        /* do nothing */
3204
                    }
×
3205

3206
                    /**
3207
                     * {@inheritDoc}
3208
                     */
3209
                    public void assertDefaultValue(String name) {
3210
                        /* do nothing */
3211
                    }
×
3212

3213
                    /**
3214
                     * {@inheritDoc}
3215
                     */
3216
                    public void assertDefaultMethodCall() {
3217
                        /* do nothing */
3218
                    }
×
3219

3220
                    /**
3221
                     * {@inheritDoc}
3222
                     */
3223
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3224
                        if ((modifier & Opcodes.ACC_ABSTRACT) != 0) {
1✔
3225
                            throw new IllegalStateException("Cannot define a record class as abstract");
×
3226
                        }
3227
                    }
1✔
3228

3229
                    /**
3230
                     * {@inheritDoc}
3231
                     */
3232
                    public void assertTypeInConstantPool() {
3233
                        /* do nothing */
3234
                    }
×
3235

3236
                    /**
3237
                     * {@inheritDoc}
3238
                     */
3239
                    public void assertMethodTypeInConstantPool() {
3240
                        /* do nothing */
3241
                    }
×
3242

3243
                    /**
3244
                     * {@inheritDoc}
3245
                     */
3246
                    public void assertHandleInConstantPool() {
3247
                        /* do nothing */
3248
                    }
×
3249

3250
                    /**
3251
                     * {@inheritDoc}
3252
                     */
3253
                    public void assertInvokeDynamic() {
3254
                        /* do nothing */
3255
                    }
×
3256

3257
                    /**
3258
                     * {@inheritDoc}
3259
                     */
3260
                    public void assertSubRoutine() {
3261
                        /* do nothing */
3262
                    }
×
3263

3264
                    /**
3265
                     * {@inheritDoc}
3266
                     */
3267
                    public void assertDynamicValueInConstantPool() {
3268
                        /* do nothing */
3269
                    }
×
3270

3271
                    /**
3272
                     * {@inheritDoc}
3273
                     */
3274
                    public void assertNestMate() {
3275
                        /* do nothing */
3276
                    }
×
3277

3278
                    /**
3279
                     * {@inheritDoc}
3280
                     */
3281
                    public void assertRecord() {
3282
                        /* do nothing */
3283
                    }
×
3284

3285
                    /**
3286
                     * {@inheritDoc}
3287
                     */
3288
                    public void assertPermittedSubclass() {
3289
                        /* do nothing */
3290
                    }
×
3291
                }
3292

3293
                /**
3294
                 * Represents the constraint of an annotation type.
3295
                 */
3296
                enum ForAnnotation implements Constraint {
1✔
3297

3298
                    /**
3299
                     * An annotation type with the constraints for the Java versions 5 to 7.
3300
                     */
3301
                    CLASSIC(true),
1✔
3302

3303
                    /**
3304
                     * An annotation type with the constraints for the Java versions 8+.
3305
                     */
3306
                    JAVA_8(false);
1✔
3307

3308
                    /**
3309
                     * {@code true} if this instance represents a classic annotation type (pre Java 8).
3310
                     */
3311
                    private final boolean classic;
3312

3313
                    /**
3314
                     * Creates a constraint for an annotation type.
3315
                     *
3316
                     * @param classic {@code true} if this instance represents a classic annotation type (pre Java 8).
3317
                     */
3318
                    ForAnnotation(boolean classic) {
1✔
3319
                        this.classic = classic;
1✔
3320
                    }
1✔
3321

3322
                    /**
3323
                     * {@inheritDoc}
3324
                     */
3325
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3326
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3327
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3328
                        }
3329
                    }
×
3330

3331
                    /**
3332
                     * {@inheritDoc}
3333
                     */
3334
                    public void assertMethod(String name,
3335
                                             boolean isAbstract,
3336
                                             boolean isPublic,
3337
                                             boolean isPrivate,
3338
                                             boolean isStatic,
3339
                                             boolean isVirtual,
3340
                                             boolean isConstructor,
3341
                                             boolean isDefaultValueIncompatible,
3342
                                             boolean isGeneric) {
3343
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3344
                            if (isConstructor) {
1✔
3345
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3346
                            } else if (classic && !isVirtual) {
1✔
3347
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 annotation type");
1✔
3348
                            } else if (!isStatic && isDefaultValueIncompatible) {
1✔
3349
                                throw new IllegalStateException("Cannot define method '" + name + "' with the given signature as an annotation type method");
1✔
3350
                            }
3351
                        }
3352
                    }
1✔
3353

3354
                    /**
3355
                     * {@inheritDoc}
3356
                     */
3357
                    public void assertAnnotation() {
3358
                        /* do nothing */
3359
                    }
1✔
3360

3361
                    /**
3362
                     * {@inheritDoc}
3363
                     */
3364
                    public void assertTypeAnnotation() {
3365
                        /* do nothing */
3366
                    }
×
3367

3368
                    /**
3369
                     * {@inheritDoc}
3370
                     */
3371
                    public void assertDefaultValue(String name) {
3372
                        /* do nothing */
3373
                    }
1✔
3374

3375
                    /**
3376
                     * {@inheritDoc}
3377
                     */
3378
                    public void assertDefaultMethodCall() {
3379
                        /* do nothing */
3380
                    }
×
3381

3382
                    /**
3383
                     * {@inheritDoc}
3384
                     */
3385
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3386
                        if ((modifier & Opcodes.ACC_INTERFACE) == 0) {
1✔
3387
                            throw new IllegalStateException("Cannot define annotation type without interface modifier");
×
3388
                        }
3389
                    }
1✔
3390

3391
                    /**
3392
                     * {@inheritDoc}
3393
                     */
3394
                    public void assertTypeInConstantPool() {
3395
                        /* do nothing */
3396
                    }
×
3397

3398
                    /**
3399
                     * {@inheritDoc}
3400
                     */
3401
                    public void assertMethodTypeInConstantPool() {
3402
                        /* do nothing */
3403
                    }
×
3404

3405
                    /**
3406
                     * {@inheritDoc}
3407
                     */
3408
                    public void assertHandleInConstantPool() {
3409
                        /* do nothing */
3410
                    }
×
3411

3412
                    /**
3413
                     * {@inheritDoc}
3414
                     */
3415
                    public void assertInvokeDynamic() {
3416
                        /* do nothing */
3417
                    }
×
3418

3419
                    /**
3420
                     * {@inheritDoc}
3421
                     */
3422
                    public void assertSubRoutine() {
3423
                        /* do nothing */
3424
                    }
×
3425

3426
                    /**
3427
                     * {@inheritDoc}
3428
                     */
3429
                    public void assertDynamicValueInConstantPool() {
3430
                        /* do nothing */
3431
                    }
×
3432

3433
                    /**
3434
                     * {@inheritDoc}
3435
                     */
3436
                    public void assertNestMate() {
3437
                        /* do nothing */
3438
                    }
×
3439

3440
                    /**
3441
                     * {@inheritDoc}
3442
                     */
3443
                    public void assertRecord() {
3444
                        /* do nothing */
3445
                    }
×
3446

3447
                    /**
3448
                     * {@inheritDoc}
3449
                     */
3450
                    public void assertPermittedSubclass() {
3451
                        /* do nothing */
3452
                    }
×
3453
                }
3454

3455
                /**
3456
                 * Represents the constraint implied by a class file version.
3457
                 */
3458
                @HashCodeAndEqualsPlugin.Enhance
3459
                class ForClassFileVersion implements Constraint {
3460

3461
                    /**
3462
                     * The enforced class file version.
3463
                     */
3464
                    private final ClassFileVersion classFileVersion;
3465

3466
                    /**
3467
                     * Creates a new constraint for the given class file version.
3468
                     *
3469
                     * @param classFileVersion The enforced class file version.
3470
                     */
3471
                    protected ForClassFileVersion(ClassFileVersion classFileVersion) {
1✔
3472
                        this.classFileVersion = classFileVersion;
1✔
3473
                    }
1✔
3474

3475
                    /**
3476
                     * {@inheritDoc}
3477
                     */
3478
                    public void assertType(int modifiers, boolean definesInterfaces, boolean isGeneric) {
3479
                        if ((modifiers & Opcodes.ACC_ANNOTATION) != 0 && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
3480
                            throw new IllegalStateException("Cannot define annotation type for class file version " + classFileVersion);
×
3481
                        } else if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3482
                            throw new IllegalStateException("Cannot define a generic type for class file version " + classFileVersion);
×
3483
                        }
3484
                    }
1✔
3485

3486
                    /**
3487
                     * {@inheritDoc}
3488
                     */
3489
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3490
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3491
                            throw new IllegalStateException("Cannot define generic field '" + name + "' for class file version " + classFileVersion);
×
3492
                        }
3493
                    }
1✔
3494

3495
                    /**
3496
                     * {@inheritDoc}
3497
                     */
3498
                    public void assertMethod(String name,
3499
                                             boolean isAbstract,
3500
                                             boolean isPublic,
3501
                                             boolean isPrivate,
3502
                                             boolean isStatic,
3503
                                             boolean isVirtual,
3504
                                             boolean isConstructor,
3505
                                             boolean isDefaultValueIncompatible,
3506
                                             boolean isGeneric) {
3507
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3508
                            throw new IllegalStateException("Cannot define generic method '" + name + "' for class file version " + classFileVersion);
×
3509
                        } else if (!isVirtual && isAbstract) {
1✔
3510
                            throw new IllegalStateException("Cannot define static or non-virtual method '" + name + "' to be abstract");
1✔
3511
                        }
3512
                    }
1✔
3513

3514
                    /**
3515
                     * {@inheritDoc}
3516
                     */
3517
                    public void assertAnnotation() {
3518
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3519
                            throw new IllegalStateException("Cannot write annotations for class file version " + classFileVersion);
1✔
3520
                        }
3521
                    }
1✔
3522

3523
                    /**
3524
                     * {@inheritDoc}
3525
                     */
3526
                    public void assertTypeAnnotation() {
3527
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3528
                            throw new IllegalStateException("Cannot write type annotations for class file version " + classFileVersion);
×
3529
                        }
3530
                    }
1✔
3531

3532
                    /**
3533
                     * {@inheritDoc}
3534
                     */
3535
                    public void assertDefaultValue(String name) {
3536
                        /* do nothing, implicitly checked by type assertion */
3537
                    }
1✔
3538

3539
                    /**
3540
                     * {@inheritDoc}
3541
                     */
3542
                    public void assertDefaultMethodCall() {
3543
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V8)) {
1✔
3544
                            throw new IllegalStateException("Cannot invoke default method for class file version " + classFileVersion);
×
3545
                        }
3546
                    }
1✔
3547

3548
                    /**
3549
                     * {@inheritDoc}
3550
                     */
3551
                    public void assertTypeInConstantPool() {
3552
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3553
                            throw new IllegalStateException("Cannot write type to constant pool for class file version " + classFileVersion);
×
3554
                        }
3555
                    }
1✔
3556

3557
                    /**
3558
                     * {@inheritDoc}
3559
                     */
3560
                    public void assertMethodTypeInConstantPool() {
3561
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3562
                            throw new IllegalStateException("Cannot write method type to constant pool for class file version " + classFileVersion);
1✔
3563
                        }
3564
                    }
1✔
3565

3566
                    /**
3567
                     * {@inheritDoc}
3568
                     */
3569
                    public void assertHandleInConstantPool() {
3570
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3571
                            throw new IllegalStateException("Cannot write method handle to constant pool for class file version " + classFileVersion);
1✔
3572
                        }
3573
                    }
1✔
3574

3575
                    /**
3576
                     * {@inheritDoc}
3577
                     */
3578
                    public void assertInvokeDynamic() {
3579
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3580
                            throw new IllegalStateException("Cannot write invoke dynamic instruction for class file version " + classFileVersion);
×
3581
                        }
3582
                    }
1✔
3583

3584
                    /**
3585
                     * {@inheritDoc}
3586
                     */
3587
                    public void assertSubRoutine() {
3588
                        if (classFileVersion.isGreaterThan(ClassFileVersion.JAVA_V5)) {
1✔
3589
                            throw new IllegalStateException("Cannot write subroutine for class file version " + classFileVersion);
×
3590
                        }
3591
                    }
1✔
3592

3593
                    /**
3594
                     * {@inheritDoc}
3595
                     */
3596
                    public void assertDynamicValueInConstantPool() {
3597
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
1✔
3598
                            throw new IllegalStateException("Cannot write dynamic constant for class file version " + classFileVersion);
1✔
3599
                        }
3600
                    }
×
3601

3602
                    /**
3603
                     * {@inheritDoc}
3604
                     */
3605
                    public void assertNestMate() {
3606
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
×
3607
                            throw new IllegalStateException("Cannot define nest mate for class file version " + classFileVersion);
×
3608
                        }
3609
                    }
×
3610

3611
                    /**
3612
                     * {@inheritDoc}
3613
                     */
3614
                    public void assertRecord() {
3615
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V14)) {
1✔
3616
                            throw new IllegalStateException("Cannot define record for class file version " + classFileVersion);
1✔
3617
                        }
3618
                    }
×
3619

3620
                    /**
3621
                     * {@inheritDoc}
3622
                     */
3623
                    public void assertPermittedSubclass() {
3624
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V17)) {
×
3625
                            throw new IllegalStateException("Cannot define permitted subclasses for class file version " + classFileVersion);
×
3626
                        }
3627
                    }
×
3628
                }
3629

3630
                /**
3631
                 * A constraint implementation that summarizes several constraints.
3632
                 */
3633
                @HashCodeAndEqualsPlugin.Enhance
3634
                class Compound implements Constraint {
3635

3636
                    /**
3637
                     * A list of constraints that is enforced in the given order.
3638
                     */
3639
                    private final List<Constraint> constraints;
3640

3641
                    /**
3642
                     * Creates a new compound constraint.
3643
                     *
3644
                     * @param constraints A list of constraints that is enforced in the given order.
3645
                     */
3646
                    public Compound(List<? extends Constraint> constraints) {
1✔
3647
                        this.constraints = new ArrayList<Constraint>();
1✔
3648
                        for (Constraint constraint : constraints) {
1✔
3649
                            if (constraint instanceof Compound) {
1✔
3650
                                this.constraints.addAll(((Compound) constraint).constraints);
×
3651
                            } else {
3652
                                this.constraints.add(constraint);
1✔
3653
                            }
3654
                        }
1✔
3655
                    }
1✔
3656

3657
                    /**
3658
                     * {@inheritDoc}
3659
                     */
3660
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3661
                        for (Constraint constraint : constraints) {
1✔
3662
                            constraint.assertType(modifier, definesInterfaces, isGeneric);
1✔
3663
                        }
1✔
3664
                    }
1✔
3665

3666
                    /**
3667
                     * {@inheritDoc}
3668
                     */
3669
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3670
                        for (Constraint constraint : constraints) {
1✔
3671
                            constraint.assertField(name, isPublic, isStatic, isFinal, isGeneric);
1✔
3672
                        }
1✔
3673
                    }
1✔
3674

3675
                    /**
3676
                     * {@inheritDoc}
3677
                     */
3678
                    public void assertMethod(String name,
3679
                                             boolean isAbstract,
3680
                                             boolean isPublic,
3681
                                             boolean isPrivate,
3682
                                             boolean isStatic,
3683
                                             boolean isVirtual,
3684
                                             boolean isConstructor,
3685
                                             boolean isDefaultValueIncompatible,
3686
                                             boolean isGeneric) {
3687
                        for (Constraint constraint : constraints) {
1✔
3688
                            constraint.assertMethod(name,
1✔
3689
                                    isAbstract,
3690
                                    isPublic,
3691
                                    isPrivate,
3692
                                    isStatic,
3693
                                    isVirtual,
3694
                                    isConstructor,
3695
                                    isDefaultValueIncompatible,
3696
                                    isGeneric);
3697
                        }
1✔
3698
                    }
1✔
3699

3700
                    /**
3701
                     * {@inheritDoc}
3702
                     */
3703
                    public void assertDefaultValue(String name) {
3704
                        for (Constraint constraint : constraints) {
1✔
3705
                            constraint.assertDefaultValue(name);
1✔
3706
                        }
1✔
3707
                    }
1✔
3708

3709
                    /**
3710
                     * {@inheritDoc}
3711
                     */
3712
                    public void assertDefaultMethodCall() {
3713
                        for (Constraint constraint : constraints) {
1✔
3714
                            constraint.assertDefaultMethodCall();
1✔
3715
                        }
1✔
3716
                    }
1✔
3717

3718
                    /**
3719
                     * {@inheritDoc}
3720
                     */
3721
                    public void assertAnnotation() {
3722
                        for (Constraint constraint : constraints) {
1✔
3723
                            constraint.assertAnnotation();
1✔
3724
                        }
1✔
3725
                    }
1✔
3726

3727
                    /**
3728
                     * {@inheritDoc}
3729
                     */
3730
                    public void assertTypeAnnotation() {
3731
                        for (Constraint constraint : constraints) {
1✔
3732
                            constraint.assertTypeAnnotation();
1✔
3733
                        }
1✔
3734
                    }
1✔
3735

3736
                    /**
3737
                     * {@inheritDoc}
3738
                     */
3739
                    public void assertTypeInConstantPool() {
3740
                        for (Constraint constraint : constraints) {
1✔
3741
                            constraint.assertTypeInConstantPool();
1✔
3742
                        }
1✔
3743
                    }
1✔
3744

3745
                    /**
3746
                     * {@inheritDoc}
3747
                     */
3748
                    public void assertMethodTypeInConstantPool() {
3749
                        for (Constraint constraint : constraints) {
1✔
3750
                            constraint.assertMethodTypeInConstantPool();
1✔
3751
                        }
1✔
3752
                    }
1✔
3753

3754
                    /**
3755
                     * {@inheritDoc}
3756
                     */
3757
                    public void assertHandleInConstantPool() {
3758
                        for (Constraint constraint : constraints) {
1✔
3759
                            constraint.assertHandleInConstantPool();
1✔
3760
                        }
1✔
3761
                    }
1✔
3762

3763
                    /**
3764
                     * {@inheritDoc}
3765
                     */
3766
                    public void assertInvokeDynamic() {
3767
                        for (Constraint constraint : constraints) {
1✔
3768
                            constraint.assertInvokeDynamic();
1✔
3769
                        }
1✔
3770
                    }
1✔
3771

3772
                    /**
3773
                     * {@inheritDoc}
3774
                     */
3775
                    public void assertSubRoutine() {
3776
                        for (Constraint constraint : constraints) {
1✔
3777
                            constraint.assertSubRoutine();
1✔
3778
                        }
1✔
3779
                    }
1✔
3780

3781
                    /**
3782
                     * {@inheritDoc}
3783
                     */
3784
                    public void assertDynamicValueInConstantPool() {
3785
                        for (Constraint constraint : constraints) {
1✔
3786
                            constraint.assertDynamicValueInConstantPool();
×
3787
                        }
×
3788
                    }
×
3789

3790
                    /**
3791
                     * {@inheritDoc}
3792
                     */
3793
                    public void assertNestMate() {
3794
                        for (Constraint constraint : constraints) {
×
3795
                            constraint.assertNestMate();
×
3796
                        }
×
3797
                    }
×
3798

3799
                    /**
3800
                     * {@inheritDoc}
3801
                     */
3802
                    public void assertRecord() {
3803
                        for (Constraint constraint : constraints) {
1✔
3804
                            constraint.assertRecord();
×
3805
                        }
×
3806
                    }
×
3807

3808
                    /**
3809
                     * {@inheritDoc}
3810
                     */
3811
                    public void assertPermittedSubclass() {
3812
                        for (Constraint constraint : constraints) {
×
3813
                            constraint.assertPermittedSubclass();
×
3814
                        }
×
3815
                    }
×
3816
                }
3817
            }
3818

3819
            /**
3820
             * A field validator for checking default values.
3821
             */
3822
            protected class ValidatingFieldVisitor extends FieldVisitor {
3823

3824
                /**
3825
                 * Creates a validating field visitor.
3826
                 *
3827
                 * @param fieldVisitor The field visitor to which any calls are delegated to.
3828
                 */
3829
                protected ValidatingFieldVisitor(FieldVisitor fieldVisitor) {
1✔
3830
                    super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
3831
                }
1✔
3832

3833
                @Override
3834
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3835
                    constraint.assertAnnotation();
1✔
3836
                    return super.visitAnnotation(descriptor, visible);
1✔
3837
                }
3838
            }
3839

3840
            /**
3841
             * A method validator for checking default values.
3842
             */
3843
            protected class ValidatingMethodVisitor extends MethodVisitor {
3844

3845
                /**
3846
                 * The name of the method being visited.
3847
                 */
3848
                private final String name;
3849

3850
                /**
3851
                 * Creates a validating method visitor.
3852
                 *
3853
                 * @param methodVisitor The method visitor to which any calls are delegated to.
3854
                 * @param name          The name of the method being visited.
3855
                 */
3856
                protected ValidatingMethodVisitor(MethodVisitor methodVisitor, String name) {
1✔
3857
                    super(OpenedClassReader.ASM_API, methodVisitor);
1✔
3858
                    this.name = name;
1✔
3859
                }
1✔
3860

3861
                @Override
3862
                @MaybeNull
3863
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3864
                    constraint.assertAnnotation();
1✔
3865
                    return super.visitAnnotation(descriptor, visible);
1✔
3866
                }
3867

3868
                @Override
3869
                @MaybeNull
3870
                public AnnotationVisitor visitAnnotationDefault() {
3871
                    constraint.assertDefaultValue(name);
1✔
3872
                    return super.visitAnnotationDefault();
1✔
3873
                }
3874

3875
                @Override
3876
                @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "Fall through to default case is intentional.")
3877
                public void visitLdcInsn(Object value) {
3878
                    if (value instanceof Type) {
1✔
3879
                        Type type = (Type) value;
1✔
3880
                        switch (type.getSort()) {
1✔
3881
                            case Type.OBJECT:
3882
                            case Type.ARRAY:
3883
                                constraint.assertTypeInConstantPool();
1✔
3884
                                break;
1✔
3885
                            case Type.METHOD:
3886
                                constraint.assertMethodTypeInConstantPool();
1✔
3887
                                break;
3888
                        }
3889
                    } else if (value instanceof Handle) {
1✔
3890
                        constraint.assertHandleInConstantPool();
1✔
3891
                    } else if (value instanceof ConstantDynamic) {
1✔
3892
                        constraint.assertDynamicValueInConstantPool();
×
3893
                    }
3894
                    super.visitLdcInsn(value);
1✔
3895
                }
1✔
3896

3897
                @Override
3898
                public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
3899
                    if (isInterface && opcode == Opcodes.INVOKESPECIAL) {
1✔
3900
                        constraint.assertDefaultMethodCall();
1✔
3901
                    }
3902
                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
1✔
3903
                }
1✔
3904

3905
                @Override
3906
                public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethod, Object... bootstrapArgument) {
3907
                    constraint.assertInvokeDynamic();
1✔
3908
                    for (Object constant : bootstrapArgument) {
1✔
3909
                        if (constant instanceof ConstantDynamic) {
1✔
3910
                            constraint.assertDynamicValueInConstantPool();
×
3911
                        }
3912
                    }
3913
                    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethod, bootstrapArgument);
1✔
3914
                }
1✔
3915

3916
                @Override
3917
                public void visitJumpInsn(int opcode, Label label) {
3918
                    if (opcode == Opcodes.JSR) {
1✔
3919
                        constraint.assertSubRoutine();
1✔
3920
                    }
3921
                    super.visitJumpInsn(opcode, label);
1✔
3922
                }
1✔
3923
            }
3924
        }
3925

3926
        /**
3927
         * A type writer that inlines the created type into an existing class file.
3928
         *
3929
         * @param <U> The best known loaded type for the dynamically created type.
3930
         */
3931
        @HashCodeAndEqualsPlugin.Enhance
3932
        public abstract static class ForInlining<U> extends Default<U> {
3933

3934
            /**
3935
             * Indicates that a field should be ignored.
3936
             */
3937
            @AlwaysNull
3938
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
3939

3940
            /**
3941
             * Indicates that a method should be ignored.
3942
             */
3943
            @AlwaysNull
3944
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
3945

3946
            /**
3947
             * Indicates that a record component should be ignored.
3948
             */
3949
            @AlwaysNull
3950
            private static final RecordComponentVisitor IGNORE_RECORD_COMPONENT = null;
1✔
3951

3952
            /**
3953
             * Indicates that an annotation should be ignored.
3954
             */
3955
            @AlwaysNull
3956
            private static final AnnotationVisitor IGNORE_ANNOTATION = null;
1✔
3957

3958
            /**
3959
             * The original type's description.
3960
             */
3961
            protected final TypeDescription originalType;
3962

3963
            /**
3964
             * The class file locator for locating the original type's class file.
3965
             */
3966
            protected final ClassFileLocator classFileLocator;
3967

3968
            /**
3969
             * Creates a new inlining type writer.
3970
             *
3971
             * @param instrumentedType             The instrumented type to be created.
3972
             * @param classFileVersion             The class file specified by the user.
3973
             * @param fieldPool                    The field pool to use.
3974
             * @param recordComponentPool          The record component pool to use.
3975
             * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
3976
             * @param fields                       The instrumented type's declared fields.
3977
             * @param methods                      The instrumented type's declared and virtually inherited methods.
3978
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
3979
             * @param recordComponents             The instrumented type's record components.
3980
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
3981
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
3982
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
3983
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
3984
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
3985
             * @param annotationRetention          The annotation retention to apply.
3986
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
3987
             * @param implementationContextFactory The implementation context factory to apply.
3988
             * @param typeValidation               Determines if a type should be explicitly validated.
3989
             * @param classReaderFactory           The class reader factory to use.
3990
             * @param classWriterFactory           The class writer factory to use.
3991
             * @param typePool                     The type pool to use for computing stack map frames, if required.
3992
             * @param originalType                 The original type's description.
3993
             * @param classFileLocator             The class file locator for locating the original type's class file.
3994
             */
3995
            protected ForInlining(TypeDescription instrumentedType,
3996
                                  ClassFileVersion classFileVersion,
3997
                                  FieldPool fieldPool,
3998
                                  RecordComponentPool recordComponentPool,
3999
                                  List<? extends DynamicType> auxiliaryTypes,
4000
                                  FieldList<FieldDescription.InDefinedShape> fields,
4001
                                  MethodList<?> methods,
4002
                                  MethodList<?> instrumentedMethods,
4003
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4004
                                  LoadedTypeInitializer loadedTypeInitializer,
4005
                                  TypeInitializer typeInitializer,
4006
                                  TypeAttributeAppender typeAttributeAppender,
4007
                                  AsmVisitorWrapper asmVisitorWrapper,
4008
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
4009
                                  AnnotationRetention annotationRetention,
4010
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4011
                                  Implementation.Context.Factory implementationContextFactory,
4012
                                  TypeValidation typeValidation,
4013
                                  AsmClassReader.Factory classReaderFactory,
4014
                                  AsmClassWriter.Factory classWriterFactory,
4015
                                  TypePool typePool,
4016
                                  TypeDescription originalType,
4017
                                  ClassFileLocator classFileLocator) {
4018
                super(instrumentedType,
1✔
4019
                        classFileVersion,
4020
                        fieldPool,
4021
                        recordComponentPool,
4022
                        auxiliaryTypes,
4023
                        fields,
4024
                        methods,
4025
                        instrumentedMethods,
4026
                        recordComponents,
4027
                        loadedTypeInitializer,
4028
                        typeInitializer,
4029
                        typeAttributeAppender,
4030
                        asmVisitorWrapper,
4031
                        annotationValueFilterFactory,
4032
                        annotationRetention,
4033
                        auxiliaryTypeNamingStrategy,
4034
                        implementationContextFactory,
4035
                        typeValidation,
4036
                        classReaderFactory,
4037
                        classWriterFactory,
4038
                        typePool);
4039
                this.originalType = originalType;
1✔
4040
                this.classFileLocator = classFileLocator;
1✔
4041
            }
1✔
4042

4043
            /**
4044
             * {@inheritDoc}
4045
             */
4046
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
4047
                ContextRegistry contextRegistry = new ContextRegistry();
1✔
4048
                return new RegistryContextClassVisitor(writeTo(ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
4049
                        typeInitializer,
4050
                        contextRegistry,
4051
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
4052
                        asmVisitorWrapper.mergeReader(readerFlags)), contextRegistry);
1✔
4053
            }
4054

4055
            @Override
4056
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
4057
                try {
4058
                    int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS);
1✔
4059
                    int readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
4060
                    byte[] binaryRepresentation = classFileLocator.locate(originalType.getName()).resolve();
1✔
4061
                    dispatcher.dump(instrumentedType, true, binaryRepresentation);
1✔
4062
                    AsmClassReader classReader = classReaderFactory.make(binaryRepresentation);
1✔
4063
                    AsmClassWriter classWriter = classWriterFactory.make(writerFlags, classReader, typePool);
1✔
4064
                    ContextRegistry contextRegistry = new ContextRegistry();
1✔
4065
                    classReader.accept(writeTo(ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
4066
                            typeInitializer,
4067
                            contextRegistry,
4068
                            writerFlags,
4069
                            readerFlags), readerFlags);
4070
                    return new UnresolvedType(classWriter.getBinaryRepresentation(), contextRegistry.getAuxiliaryTypes());
1✔
4071
                } catch (IOException exception) {
×
4072
                    throw new RuntimeException("The class file could not be written", exception);
×
4073
                }
4074
            }
4075

4076
            /**
4077
             * Creates a class visitor which weaves all changes and additions on the fly.
4078
             *
4079
             * @param classVisitor    The class visitor to which this entry is to be written to.
4080
             * @param typeInitializer The type initializer to apply.
4081
             * @param contextRegistry A context registry to register the lazily created implementation context to.
4082
             * @param writerFlags     The writer flags being used.
4083
             * @param readerFlags     The reader flags being used.
4084
             * @return A class visitor which is capable of applying the changes.
4085
             */
4086
            protected abstract ClassVisitor writeTo(ClassVisitor classVisitor,
4087
                                                    TypeInitializer typeInitializer,
4088
                                                    ContextRegistry contextRegistry,
4089
                                                    int writerFlags,
4090
                                                    int readerFlags);
4091

4092
            /**
4093
             * A context class visitor based on a {@link ContextRegistry}.
4094
             */
4095
            protected class RegistryContextClassVisitor extends ContextClassVisitor {
4096

4097
                /**
4098
                 * The context registry to use.
4099
                 */
4100
                private final ContextRegistry contextRegistry;
4101

4102
                /**
4103
                 * Creates a new context class visitor based on a {@link ContextRegistry}.
4104
                 *
4105
                 * @param classVisitor    The class visitor to delegate to.
4106
                 * @param contextRegistry The context registry to use.
4107
                 */
4108
                protected RegistryContextClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry) {
1✔
4109
                    super(classVisitor);
1✔
4110
                    this.contextRegistry = contextRegistry;
1✔
4111
                }
1✔
4112

4113
                @Override
4114
                public List<DynamicType> getAuxiliaryTypes() {
4115
                    return CompoundList.of(auxiliaryTypes, contextRegistry.getAuxiliaryTypes());
1✔
4116
                }
4117

4118
                @Override
4119
                public LoadedTypeInitializer getLoadedTypeInitializer() {
4120
                    return loadedTypeInitializer;
1✔
4121
                }
4122
            }
4123

4124
            /**
4125
             * A context registry allows to extract auxiliary types from a lazily created implementation context.
4126
             */
4127
            protected static class ContextRegistry {
1✔
4128

4129
                /**
4130
                 * The implementation context that is used for creating a class or {@code null} if it was not registered.
4131
                 */
4132
                @UnknownNull
4133
                private Implementation.Context.ExtractableView implementationContext;
4134

4135
                /**
4136
                 * Registers the implementation context.
4137
                 *
4138
                 * @param implementationContext The implementation context.
4139
                 */
4140
                public void setImplementationContext(Implementation.Context.ExtractableView implementationContext) {
4141
                    this.implementationContext = implementationContext;
1✔
4142
                }
1✔
4143

4144
                /**
4145
                 * Returns the auxiliary types that were registered during class creation. This method must only be called after
4146
                 * a class was created.
4147
                 *
4148
                 * @return The auxiliary types that were registered during class creation
4149
                 */
4150
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Lazy value definition is intended.")
4151
                public List<DynamicType> getAuxiliaryTypes() {
4152
                    return implementationContext.getAuxiliaryTypes();
1✔
4153
                }
4154
            }
4155

4156
            /**
4157
             * A default type writer that reprocesses a type completely.
4158
             *
4159
             * @param <V> The best known loaded type for the dynamically created type.
4160
             */
4161
            @HashCodeAndEqualsPlugin.Enhance
4162
            protected static class WithFullProcessing<V> extends ForInlining<V> {
4163

4164
                /**
4165
                 * An empty array to indicate missing frames.
4166
                 */
4167
                private static final Object[] EMPTY = new Object[0];
1✔
4168

4169
                /**
4170
                 * The method registry to use.
4171
                 */
4172
                private final MethodRegistry.Prepared methodRegistry;
4173

4174
                /**
4175
                 * The implementation target factory to use.
4176
                 */
4177
                private final Implementation.Target.Factory implementationTargetFactory;
4178

4179
                /**
4180
                 * The method rebase resolver to use for rebasing methods.
4181
                 */
4182
                private final MethodRebaseResolver methodRebaseResolver;
4183

4184
                /**
4185
                 * Creates a new inlining type writer that fully reprocesses a type.
4186
                 *
4187
                 * @param instrumentedType             The instrumented type to be created.
4188
                 * @param classFileVersion             The class file specified by the user.
4189
                 * @param fieldPool                    The field pool to use.
4190
                 * @param recordComponentPool          The record component pool to use.
4191
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
4192
                 * @param fields                       The instrumented type's declared fields.
4193
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
4194
                 * @param instrumentedMethods          The instrumented methods relevant to this type creation.
4195
                 * @param recordComponents             The instrumented type's record components.
4196
                 * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
4197
                 * @param typeInitializer              The type initializer to include in the created type's type initializer.
4198
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
4199
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
4200
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
4201
                 * @param annotationRetention          The annotation retention to apply.
4202
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
4203
                 * @param implementationContextFactory The implementation context factory to apply.
4204
                 * @param typeValidation               Determines if a type should be explicitly validated.
4205
                 * @param classReaderFactory           The class reader factory to use.
4206
                 * @param classWriterFactory           The class writer factory to use.
4207
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
4208
                 * @param originalType                 The original type's description.
4209
                 * @param classFileLocator             The class file locator for locating the original type's class file.
4210
                 * @param methodRegistry               The method registry to use.
4211
                 * @param implementationTargetFactory  The implementation target factory to use.
4212
                 * @param methodRebaseResolver         The method rebase resolver to use for rebasing methods.
4213
                 */
4214
                protected WithFullProcessing(TypeDescription instrumentedType,
4215
                                             ClassFileVersion classFileVersion,
4216
                                             FieldPool fieldPool,
4217
                                             RecordComponentPool recordComponentPool,
4218
                                             List<? extends DynamicType> auxiliaryTypes,
4219
                                             FieldList<FieldDescription.InDefinedShape> fields,
4220
                                             MethodList<?> methods, MethodList<?> instrumentedMethods,
4221
                                             RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4222
                                             LoadedTypeInitializer loadedTypeInitializer,
4223
                                             TypeInitializer typeInitializer,
4224
                                             TypeAttributeAppender typeAttributeAppender,
4225
                                             AsmVisitorWrapper asmVisitorWrapper,
4226
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
4227
                                             AnnotationRetention annotationRetention,
4228
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4229
                                             Implementation.Context.Factory implementationContextFactory,
4230
                                             TypeValidation typeValidation,
4231
                                             AsmClassReader.Factory classReaderFactory,
4232
                                             AsmClassWriter.Factory classWriterFactory,
4233
                                             TypePool typePool,
4234
                                             TypeDescription originalType,
4235
                                             ClassFileLocator classFileLocator,
4236
                                             MethodRegistry.Prepared methodRegistry,
4237
                                             Implementation.Target.Factory implementationTargetFactory,
4238
                                             MethodRebaseResolver methodRebaseResolver) {
4239
                    super(instrumentedType,
1✔
4240
                            classFileVersion,
4241
                            fieldPool,
4242
                            recordComponentPool,
4243
                            auxiliaryTypes,
4244
                            fields,
4245
                            methods,
4246
                            instrumentedMethods,
4247
                            recordComponents,
4248
                            loadedTypeInitializer,
4249
                            typeInitializer,
4250
                            typeAttributeAppender,
4251
                            asmVisitorWrapper,
4252
                            annotationValueFilterFactory,
4253
                            annotationRetention,
4254
                            auxiliaryTypeNamingStrategy,
4255
                            implementationContextFactory,
4256
                            typeValidation,
4257
                            classReaderFactory,
4258
                            classWriterFactory,
4259
                            typePool,
4260
                            originalType,
4261
                            classFileLocator);
4262
                    this.methodRegistry = methodRegistry;
1✔
4263
                    this.implementationTargetFactory = implementationTargetFactory;
1✔
4264
                    this.methodRebaseResolver = methodRebaseResolver;
1✔
4265
                }
1✔
4266

4267
                /**
4268
                 * {@inheritDoc}
4269
                 */
4270
                protected ClassVisitor writeTo(ClassVisitor classVisitor, TypeInitializer typeInitializer, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
4271
                    classVisitor = new RedefinitionClassVisitor(classVisitor, typeInitializer, contextRegistry, writerFlags, readerFlags);
1✔
4272
                    return originalType.getName().equals(instrumentedType.getName())
1✔
4273
                            ? classVisitor
4274
                            : new OpenedClassRemapper(classVisitor, new SimpleRemapper(OpenedClassReader.ASM_API, originalType.getInternalName(), instrumentedType.getInternalName()));
1✔
4275
                }
4276

4277
                /**
4278
                 * A {@link ClassRemapper} that uses the Byte Buddy-defined API version.
4279
                 */
4280
                protected static class OpenedClassRemapper extends ClassRemapper {
4281

4282
                    /**
4283
                     * Creates a new opened class remapper.
4284
                     *
4285
                     * @param classVisitor The class visitor to wrap
4286
                     * @param remapper     The remapper to apply.
4287
                     */
4288
                    protected OpenedClassRemapper(ClassVisitor classVisitor, Remapper remapper) {
4289
                        super(OpenedClassReader.ASM_API, classVisitor, remapper);
1✔
4290
                    }
1✔
4291
                }
4292

4293
                /**
4294
                 * An initialization handler is responsible for handling the creation of the type initializer.
4295
                 */
4296
                protected interface InitializationHandler {
4297

4298
                    /**
4299
                     * Invoked upon completion of writing the instrumented type.
4300
                     *
4301
                     * @param classVisitor          The class visitor to write any methods to.
4302
                     * @param implementationContext The implementation context to use.
4303
                     */
4304
                    void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext);
4305

4306
                    /**
4307
                     * An initialization handler that creates a new type initializer.
4308
                     */
4309
                    class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4310

4311
                        /**
4312
                         * Creates a new creating initialization handler.
4313
                         *
4314
                         * @param instrumentedType             The instrumented type.
4315
                         * @param methodPool                   The method pool to use.
4316
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4317
                         */
4318
                        protected Creating(TypeDescription instrumentedType,
4319
                                           MethodPool methodPool,
4320
                                           AnnotationValueFilter.Factory annotationValueFilterFactory) {
4321
                            super(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
4322
                        }
1✔
4323

4324
                        /**
4325
                         * {@inheritDoc}
4326
                         */
4327
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4328
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4329
                        }
1✔
4330
                    }
4331

4332
                    /**
4333
                     * An initialization handler that appends code to a previously visited type initializer.
4334
                     */
4335
                    abstract class Appending extends MethodVisitor implements InitializationHandler, TypeInitializer.Drain {
4336

4337
                        /**
4338
                         * The instrumented type.
4339
                         */
4340
                        protected final TypeDescription instrumentedType;
4341

4342
                        /**
4343
                         * The method pool record for the type initializer.
4344
                         */
4345
                        protected final MethodPool.Record record;
4346

4347
                        /**
4348
                         * The used annotation value filter factory.
4349
                         */
4350
                        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4351

4352
                        /**
4353
                         * The frame writer to use.
4354
                         */
4355
                        protected final FrameWriter frameWriter;
4356

4357
                        /**
4358
                         * The currently recorded stack size.
4359
                         */
4360
                        protected int stackSize;
4361

4362
                        /**
4363
                         * The currently recorded local variable length.
4364
                         */
4365
                        protected int localVariableLength;
4366

4367
                        /**
4368
                         * Creates a new appending initialization handler.
4369
                         *
4370
                         * @param methodVisitor                The underlying method visitor.
4371
                         * @param instrumentedType             The instrumented type.
4372
                         * @param record                       The method pool record for the type initializer.
4373
                         * @param annotationValueFilterFactory The used annotation value filter factory.
4374
                         * @param requireFrames                {@code true} if the visitor is required to add frames.
4375
                         * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4376
                         */
4377
                        protected Appending(MethodVisitor methodVisitor,
4378
                                            TypeDescription instrumentedType,
4379
                                            MethodPool.Record record,
4380
                                            AnnotationValueFilter.Factory annotationValueFilterFactory,
4381
                                            boolean requireFrames,
4382
                                            boolean expandFrames) {
4383
                            super(OpenedClassReader.ASM_API, methodVisitor);
1✔
4384
                            this.instrumentedType = instrumentedType;
1✔
4385
                            this.record = record;
1✔
4386
                            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
4387
                            if (!requireFrames) {
1✔
4388
                                frameWriter = FrameWriter.NoOp.INSTANCE;
1✔
4389
                            } else if (expandFrames) {
1✔
4390
                                frameWriter = FrameWriter.Expanding.INSTANCE;
×
4391
                            } else {
4392
                                frameWriter = new FrameWriter.Active();
1✔
4393
                            }
4394
                        }
1✔
4395

4396
                        /**
4397
                         * Resolves an initialization handler.
4398
                         *
4399
                         * @param enabled                      {@code true} if the implementation context is enabled, i.e. any {@link TypeInitializer} might be active.
4400
                         * @param methodVisitor                The delegation method visitor.
4401
                         * @param instrumentedType             The instrumented type.
4402
                         * @param methodPool                   The method pool to use.
4403
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4404
                         * @param requireFrames                {@code true} if frames must be computed.
4405
                         * @param expandFrames                 {@code true} if frames must be expanded.
4406
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4407
                         */
4408
                        protected static InitializationHandler of(boolean enabled,
4409
                                                                  MethodVisitor methodVisitor,
4410
                                                                  TypeDescription instrumentedType,
4411
                                                                  MethodPool methodPool,
4412
                                                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
4413
                                                                  boolean requireFrames,
4414
                                                                  boolean expandFrames) {
4415
                            return enabled
1✔
4416
                                    ? withDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames)
1✔
4417
                                    : withoutDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4418
                        }
4419

4420
                        /**
4421
                         * Resolves an initialization handler with a drain.
4422
                         *
4423
                         * @param methodVisitor                The delegation method visitor.
4424
                         * @param instrumentedType             The instrumented type.
4425
                         * @param methodPool                   The method pool to use.
4426
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4427
                         * @param requireFrames                {@code true} if frames must be computed.
4428
                         * @param expandFrames                 {@code true} if frames must be expanded.
4429
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4430
                         */
4431
                        private static WithDrain withDrain(MethodVisitor methodVisitor,
4432
                                                           TypeDescription instrumentedType,
4433
                                                           MethodPool methodPool,
4434
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4435
                                                           boolean requireFrames,
4436
                                                           boolean expandFrames) {
4437
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4438
                            return record.getSort().isImplemented()
1✔
4439
                                    ? new WithDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4440
                                    : new WithDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4441
                        }
4442

4443
                        /**
4444
                         * Resolves an initialization handler without a drain.
4445
                         *
4446
                         * @param methodVisitor                The delegation method visitor.
4447
                         * @param instrumentedType             The instrumented type.
4448
                         * @param methodPool                   The method pool to use.
4449
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4450
                         * @param requireFrames                {@code true} if frames must be computed.
4451
                         * @param expandFrames                 {@code true} if frames must be expanded.
4452
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4453
                         */
4454
                        private static WithoutDrain withoutDrain(MethodVisitor methodVisitor,
4455
                                                                 TypeDescription instrumentedType,
4456
                                                                 MethodPool methodPool,
4457
                                                                 AnnotationValueFilter.Factory annotationValueFilterFactory,
4458
                                                                 boolean requireFrames,
4459
                                                                 boolean expandFrames) {
4460
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4461
                            return record.getSort().isImplemented()
1✔
4462
                                    ? new WithoutDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4463
                                    : new WithoutDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory);
4464
                        }
4465

4466
                        @Override
4467
                        public void visitCode() {
4468
                            record.applyAttributes(mv, annotationValueFilterFactory);
1✔
4469
                            super.visitCode();
1✔
4470
                            onStart();
1✔
4471
                        }
1✔
4472

4473
                        /**
4474
                         * Invoked after the user code was visited.
4475
                         */
4476
                        protected abstract void onStart();
4477

4478
                        @Override
4479
                        public void visitFrame(int type, int localVariableLength, @MaybeNull Object[] localVariable, int stackSize, @MaybeNull Object[] stack) {
4480
                            super.visitFrame(type, localVariableLength, localVariable, stackSize, stack);
1✔
4481
                            frameWriter.onFrame(type, localVariableLength);
1✔
4482
                        }
1✔
4483

4484
                        @Override
4485
                        public void visitMaxs(int stackSize, int localVariableLength) {
4486
                            this.stackSize = stackSize;
1✔
4487
                            this.localVariableLength = localVariableLength;
1✔
4488
                        }
1✔
4489

4490
                        @Override
4491
                        public abstract void visitEnd();
4492

4493
                        /**
4494
                         * {@inheritDoc}
4495
                         */
4496
                        public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
4497
                            ByteCodeAppender.Size size = typeInitializer.apply(mv, implementationContext, new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4498
                            stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4499
                            localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4500
                            onComplete(implementationContext);
1✔
4501
                        }
1✔
4502

4503
                        /**
4504
                         * Invoked upon completion of writing the type initializer.
4505
                         *
4506
                         * @param implementationContext The implementation context to use.
4507
                         */
4508
                        protected abstract void onComplete(Implementation.Context implementationContext);
4509

4510
                        /**
4511
                         * {@inheritDoc}
4512
                         */
4513
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4514
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4515
                            mv.visitMaxs(stackSize, localVariableLength);
1✔
4516
                            mv.visitEnd();
1✔
4517
                        }
1✔
4518

4519
                        /**
4520
                         * A frame writer is responsible for adding empty frames on jump instructions.
4521
                         */
4522
                        protected interface FrameWriter {
4523

4524
                            /**
4525
                             * An empty array.
4526
                             */
4527
                            Object[] EMPTY = new Object[0];
1✔
4528

4529
                            /**
4530
                             * Informs this frame writer of an observed frame.
4531
                             *
4532
                             * @param type                The frame type.
4533
                             * @param localVariableLength The length of the local variables array.
4534
                             */
4535
                            void onFrame(int type, int localVariableLength);
4536

4537
                            /**
4538
                             * Emits an empty frame.
4539
                             *
4540
                             * @param methodVisitor The method visitor to write the frame to.
4541
                             */
4542
                            void emitFrame(MethodVisitor methodVisitor);
4543

4544
                            /**
4545
                             * A non-operational frame writer.
4546
                             */
4547
                            enum NoOp implements FrameWriter {
1✔
4548

4549
                                /**
4550
                                 * The singleton instance.
4551
                                 */
4552
                                INSTANCE;
1✔
4553

4554
                                /**
4555
                                 * {@inheritDoc}
4556
                                 */
4557
                                public void onFrame(int type, int localVariableLength) {
4558
                                    /* do nothing */
4559
                                }
1✔
4560

4561
                                /**
4562
                                 * {@inheritDoc}
4563
                                 */
4564
                                public void emitFrame(MethodVisitor methodVisitor) {
4565
                                    /* do nothing */
4566
                                }
1✔
4567
                            }
4568

4569
                            /**
4570
                             * A frame writer that creates an expanded frame.
4571
                             */
4572
                            enum Expanding implements FrameWriter {
1✔
4573

4574
                                /**
4575
                                 * The singleton instance.
4576
                                 */
4577
                                INSTANCE;
1✔
4578

4579
                                /**
4580
                                 * {@inheritDoc}
4581
                                 */
4582
                                public void onFrame(int type, int localVariableLength) {
4583
                                    /* do nothing */
4584
                                }
1✔
4585

4586
                                /**
4587
                                 * {@inheritDoc}
4588
                                 */
4589
                                public void emitFrame(MethodVisitor methodVisitor) {
4590
                                    methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4591
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4592
                                }
1✔
4593
                            }
4594

4595
                            /**
4596
                             * An active frame writer that creates the most efficient frame.
4597
                             */
4598
                            class Active implements FrameWriter {
1✔
4599

4600
                                /**
4601
                                 * The current length of the current local variable array.
4602
                                 */
4603
                                private int currentLocalVariableLength;
4604

4605
                                /**
4606
                                 * {@inheritDoc}
4607
                                 */
4608
                                public void onFrame(int type, int localVariableLength) {
4609
                                    switch (type) {
1✔
4610
                                        case Opcodes.F_SAME:
4611
                                        case Opcodes.F_SAME1:
4612
                                            break;
1✔
4613
                                        case Opcodes.F_APPEND:
4614
                                            currentLocalVariableLength += localVariableLength;
1✔
4615
                                            break;
1✔
4616
                                        case Opcodes.F_CHOP:
4617
                                            currentLocalVariableLength -= localVariableLength;
1✔
4618
                                            break;
1✔
4619
                                        case Opcodes.F_NEW:
4620
                                        case Opcodes.F_FULL:
4621
                                            currentLocalVariableLength = localVariableLength;
1✔
4622
                                            break;
1✔
4623
                                        default:
4624
                                            throw new IllegalStateException("Unexpected frame type: " + type);
1✔
4625
                                    }
4626
                                }
1✔
4627

4628
                                /**
4629
                                 * {@inheritDoc}
4630
                                 */
4631
                                public void emitFrame(MethodVisitor methodVisitor) {
4632
                                    if (currentLocalVariableLength == 0) {
1✔
4633
                                        methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4634
                                    } else if (currentLocalVariableLength > 3) {
1✔
4635
                                        methodVisitor.visitFrame(Opcodes.F_FULL, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4636
                                    } else {
4637
                                        methodVisitor.visitFrame(Opcodes.F_CHOP, currentLocalVariableLength, EMPTY, EMPTY.length, EMPTY);
1✔
4638
                                    }
4639
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4640
                                    currentLocalVariableLength = 0;
1✔
4641
                                }
1✔
4642
                            }
4643
                        }
4644

4645
                        /**
4646
                         * An initialization handler that appends code to a previously visited type initializer without allowing active
4647
                         * {@link TypeInitializer} registrations.
4648
                         */
4649
                        protected abstract static class WithoutDrain extends Appending {
4650

4651
                            /**
4652
                             * Creates a new appending initialization handler without a drain.
4653
                             *
4654
                             * @param methodVisitor                The underlying method visitor.
4655
                             * @param instrumentedType             The instrumented type.
4656
                             * @param record                       The method pool record for the type initializer.
4657
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4658
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4659
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4660
                             */
4661
                            protected WithoutDrain(MethodVisitor methodVisitor,
4662
                                                   TypeDescription instrumentedType,
4663
                                                   MethodPool.Record record,
4664
                                                   AnnotationValueFilter.Factory annotationValueFilterFactory,
4665
                                                   boolean requireFrames,
4666
                                                   boolean expandFrames) {
4667
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4668
                            }
1✔
4669

4670
                            @Override
4671
                            protected void onStart() {
4672
                                /* do nothing */
4673
                            }
1✔
4674

4675
                            @Override
4676
                            public void visitEnd() {
4677
                                /* do nothing */
4678
                            }
1✔
4679

4680
                            /**
4681
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4682
                             * {@link TypeInitializer} registrations and without an active record.
4683
                             */
4684
                            protected static class WithoutActiveRecord extends WithoutDrain {
4685

4686
                                /**
4687
                                 * Creates a new appending initialization handler without a drain and without an active record.
4688
                                 *
4689
                                 * @param methodVisitor                The underlying method visitor.
4690
                                 * @param instrumentedType             The instrumented type.
4691
                                 * @param record                       The method pool record for the type initializer.
4692
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4693
                                 */
4694
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4695
                                                              TypeDescription instrumentedType,
4696
                                                              MethodPool.Record record,
4697
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory) {
4698
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, false, false);
1✔
4699
                                }
1✔
4700

4701
                                @Override
4702
                                protected void onComplete(Implementation.Context implementationContext) {
4703
                                    /* do nothing */
4704
                                }
1✔
4705
                            }
4706

4707
                            /**
4708
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4709
                             * {@link TypeInitializer} registrations and with an active record.
4710
                             */
4711
                            protected static class WithActiveRecord extends WithoutDrain {
4712

4713
                                /**
4714
                                 * The label that indicates the beginning of the active record.
4715
                                 */
4716
                                private final Label label;
4717

4718
                                /**
4719
                                 * Creates a new appending initialization handler without a drain and with an active record.
4720
                                 *
4721
                                 * @param methodVisitor                The underlying method visitor.
4722
                                 * @param instrumentedType             The instrumented type.
4723
                                 * @param record                       The method pool record for the type initializer.
4724
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4725
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4726
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4727
                                 */
4728
                                protected WithActiveRecord(MethodVisitor methodVisitor,
4729
                                                           TypeDescription instrumentedType,
4730
                                                           MethodPool.Record record,
4731
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4732
                                                           boolean requireFrames,
4733
                                                           boolean expandFrames) {
4734
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4735
                                    label = new Label();
1✔
4736
                                }
1✔
4737

4738
                                @Override
4739
                                public void visitInsn(int opcode) {
4740
                                    if (opcode == Opcodes.RETURN) {
1✔
4741
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4742
                                    } else {
4743
                                        super.visitInsn(opcode);
1✔
4744
                                    }
4745
                                }
1✔
4746

4747
                                @Override
4748
                                protected void onComplete(Implementation.Context implementationContext) {
4749
                                    mv.visitLabel(label);
1✔
4750
                                    frameWriter.emitFrame(mv);
1✔
4751
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4752
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4753
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4754
                                }
1✔
4755

4756
                            }
4757
                        }
4758

4759
                        /**
4760
                         * An initialization handler that appends code to a previously visited type initializer with allowing active
4761
                         * {@link TypeInitializer} registrations.
4762
                         */
4763
                        protected abstract static class WithDrain extends Appending {
4764

4765
                            /**
4766
                             * A label marking the beginning of the appended code.
4767
                             */
4768
                            protected final Label appended;
4769

4770
                            /**
4771
                             * A label marking the beginning og the original type initializer's code.
4772
                             */
4773
                            protected final Label original;
4774

4775
                            /**
4776
                             * Creates a new appending initialization handler with a drain.
4777
                             *
4778
                             * @param methodVisitor                The underlying method visitor.
4779
                             * @param instrumentedType             The instrumented type.
4780
                             * @param record                       The method pool record for the type initializer.
4781
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4782
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4783
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4784
                             */
4785
                            protected WithDrain(MethodVisitor methodVisitor,
4786
                                                TypeDescription instrumentedType,
4787
                                                MethodPool.Record record,
4788
                                                AnnotationValueFilter.Factory annotationValueFilterFactory,
4789
                                                boolean requireFrames,
4790
                                                boolean expandFrames) {
4791
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4792
                                appended = new Label();
1✔
4793
                                original = new Label();
1✔
4794
                            }
1✔
4795

4796
                            @Override
4797
                            protected void onStart() {
4798
                                mv.visitJumpInsn(Opcodes.GOTO, appended);
1✔
4799
                                mv.visitLabel(original);
1✔
4800
                                frameWriter.emitFrame(mv);
1✔
4801
                            }
1✔
4802

4803
                            @Override
4804
                            public void visitEnd() {
4805
                                mv.visitLabel(appended);
1✔
4806
                                frameWriter.emitFrame(mv);
1✔
4807
                            }
1✔
4808

4809
                            @Override
4810
                            protected void onComplete(Implementation.Context implementationContext) {
4811
                                mv.visitJumpInsn(Opcodes.GOTO, original);
1✔
4812
                                onAfterComplete(implementationContext);
1✔
4813
                            }
1✔
4814

4815
                            /**
4816
                             * Invoked after completion of writing the type initializer.
4817
                             *
4818
                             * @param implementationContext The implementation context to use.
4819
                             */
4820
                            protected abstract void onAfterComplete(Implementation.Context implementationContext);
4821

4822
                            /**
4823
                             * A code appending initialization handler with a drain that does not apply an explicit record.
4824
                             */
4825
                            protected static class WithoutActiveRecord extends WithDrain {
4826

4827
                                /**
4828
                                 * Creates a new appending initialization handler with a drain and without an active record.
4829
                                 *
4830
                                 * @param methodVisitor                The underlying method visitor.
4831
                                 * @param instrumentedType             The instrumented type.
4832
                                 * @param record                       The method pool record for the type initializer.
4833
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4834
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4835
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4836
                                 */
4837
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4838
                                                              TypeDescription instrumentedType,
4839
                                                              MethodPool.Record record,
4840
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory,
4841
                                                              boolean requireFrames,
4842
                                                              boolean expandFrames) {
4843
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4844
                                }
1✔
4845

4846
                                @Override
4847
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4848
                                    /* do nothing */
4849
                                }
1✔
4850
                            }
4851

4852
                            /**
4853
                             * A code appending initialization handler with a drain that applies an explicit record.
4854
                             */
4855
                            protected static class WithActiveRecord extends WithDrain {
4856

4857
                                /**
4858
                                 * A label indicating the beginning of the record's code.
4859
                                 */
4860
                                private final Label label;
4861

4862
                                /**
4863
                                 * Creates a new appending initialization handler with a drain and with an active record.
4864
                                 *
4865
                                 * @param methodVisitor                The underlying method visitor.
4866
                                 * @param instrumentedType             The instrumented type.
4867
                                 * @param record                       The method pool record for the type initializer.
4868
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4869
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4870
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4871
                                 */
4872
                                protected WithActiveRecord(MethodVisitor methodVisitor,
4873
                                                           TypeDescription instrumentedType,
4874
                                                           MethodPool.Record record,
4875
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4876
                                                           boolean requireFrames,
4877
                                                           boolean expandFrames) {
4878
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4879
                                    label = new Label();
1✔
4880
                                }
1✔
4881

4882
                                @Override
4883
                                public void visitInsn(int opcode) {
4884
                                    if (opcode == Opcodes.RETURN) {
1✔
4885
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4886
                                    } else {
4887
                                        super.visitInsn(opcode);
1✔
4888
                                    }
4889
                                }
1✔
4890

4891
                                @Override
4892
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4893
                                    mv.visitLabel(label);
1✔
4894
                                    frameWriter.emitFrame(mv);
1✔
4895
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4896
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4897
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4898
                                }
1✔
4899
                            }
4900
                        }
4901
                    }
4902
                }
4903

4904
                /**
4905
                 * A class visitor which is capable of applying a redefinition of an existing class file.
4906
                 */
4907
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
4908
                protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
4909

4910
                    /**
4911
                     * The type initializer to apply.
4912
                     */
4913
                    private final TypeInitializer typeInitializer;
4914

4915
                    /**
4916
                     * A context registry to register the lazily created implementation context to.
4917
                     */
4918
                    private final ContextRegistry contextRegistry;
4919

4920
                    /**
4921
                     * The writer flags being used.
4922
                     */
4923
                    private final int writerFlags;
4924

4925
                    /**
4926
                     * The reader flags being used.
4927
                     */
4928
                    private final int readerFlags;
4929

4930
                    /**
4931
                     * A mapping of fields to write by their unique signature.
4932
                     */
4933
                    private final LinkedHashMap<SignatureKey, FieldDescription> declarableFields;
4934

4935
                    /**
4936
                     * A mapping of methods to write by their unique signature.
4937
                     */
4938
                    private final LinkedHashMap<SignatureKey, MethodDescription> declarableMethods;
4939

4940
                    /**
4941
                     * A mapping of record components to write by their names.
4942
                     */
4943
                    private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
4944

4945
                    /**
4946
                     * 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.
4947
                     */
4948
                    private final Set<String> nestMembers;
4949

4950
                    /**
4951
                     * A mapping of the internal names of all declared types to their description.
4952
                     */
4953
                    private final LinkedHashMap<String, TypeDescription> declaredTypes;
4954

4955
                    /**
4956
                     * A list of internal names of permitted subclasses to include.
4957
                     */
4958
                    @MaybeNull
4959
                    private final Set<String> permittedSubclasses;
4960

4961
                    /**
4962
                     * The method pool to use or {@code null} if the pool was not yet initialized.
4963
                     */
4964
                    @UnknownNull
4965
                    private MethodPool methodPool;
4966

4967
                    /**
4968
                     * The initialization handler to use or {@code null} if the handler was not yet initialized.
4969
                     */
4970
                    @UnknownNull
4971
                    private InitializationHandler initializationHandler;
4972

4973
                    /**
4974
                     * The implementation context for this class creation or {@code null} if it was not yet created.
4975
                     */
4976
                    @UnknownNull
4977
                    private Implementation.Context.ExtractableView implementationContext;
4978

4979
                    /**
4980
                     * {@code true} if the modifiers for deprecation should be retained.
4981
                     */
4982
                    private boolean retainDeprecationModifiers;
4983

4984
                    /**
4985
                     * A set of keys for fields that were previosuly visited.
4986
                     */
4987
                    private final Set<SignatureKey> fieldKeys = new HashSet<SignatureKey>();
1✔
4988

4989
                    /**
4990
                     * A set of keys for methods that were previosuly visited.
4991
                     */
4992
                    private final Set<SignatureKey> methodsKeys = new HashSet<SignatureKey>();
1✔
4993

4994
                    /**
4995
                     * Creates a class visitor which is capable of redefining an existent class on the fly.
4996
                     *
4997
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
4998
                     * @param typeInitializer The type initializer to apply.
4999
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
5000
                     * @param writerFlags     The writer flags being used.
5001
                     * @param readerFlags     The reader flags being used.
5002
                     */
5003
                    protected RedefinitionClassVisitor(ClassVisitor classVisitor,
5004
                                                       TypeInitializer typeInitializer,
5005
                                                       ContextRegistry contextRegistry,
5006
                                                       int writerFlags,
5007
                                                       int readerFlags) {
1✔
5008
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
5009
                        this.typeInitializer = typeInitializer;
1✔
5010
                        this.contextRegistry = contextRegistry;
1✔
5011
                        this.writerFlags = writerFlags;
1✔
5012
                        this.readerFlags = readerFlags;
1✔
5013
                        declarableFields = new LinkedHashMap<SignatureKey, FieldDescription>((int) Math.ceil(fields.size() / 0.75));
1✔
5014
                        for (FieldDescription fieldDescription : fields) {
1✔
5015
                            declarableFields.put(new SignatureKey(fieldDescription.getInternalName(), fieldDescription.getDescriptor()), fieldDescription);
1✔
5016
                        }
1✔
5017
                        declarableMethods = new LinkedHashMap<SignatureKey, MethodDescription>((int) Math.ceil(instrumentedMethods.size() / 0.75));
1✔
5018
                        for (MethodDescription methodDescription : instrumentedMethods) {
1✔
5019
                            declarableMethods.put(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()), methodDescription);
1✔
5020
                        }
1✔
5021
                        declarableRecordComponents = new LinkedHashMap<String, RecordComponentDescription>((int) Math.ceil(recordComponents.size() / 0.75));
1✔
5022
                        for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
5023
                            declarableRecordComponents.put(recordComponentDescription.getActualName(), recordComponentDescription);
×
5024
                        }
×
5025
                        if (instrumentedType.isNestHost()) {
1✔
5026
                            nestMembers = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getNestMembers().size() / 0.75));
1✔
5027
                            for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
5028
                                nestMembers.add(typeDescription.getInternalName());
×
5029
                            }
1✔
5030
                        } else {
5031
                            nestMembers = Collections.emptySet();
×
5032
                        }
5033
                        declaredTypes = new LinkedHashMap<String, TypeDescription>((int) Math.ceil(instrumentedType.getDeclaredTypes().size() / 0.75));
1✔
5034
                        for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
5035
                            declaredTypes.put(typeDescription.getInternalName(), typeDescription);
1✔
5036
                        }
1✔
5037
                        if (instrumentedType.isSealed()) {
1✔
5038
                            permittedSubclasses = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getPermittedSubtypes().size() / 0.75));
×
5039
                            for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
×
5040
                                permittedSubclasses.add(typeDescription.getInternalName());
×
5041
                            }
×
5042
                        } else {
5043
                            permittedSubclasses = null;
1✔
5044
                        }
5045
                    }
1✔
5046

5047
                    @Override
5048
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
5049
                    public void visit(int classFileVersionNumber,
5050
                                      int modifiers,
5051
                                      String internalName,
5052
                                      String genericSignature,
5053
                                      String superClassInternalName,
5054
                                      String[] interfaceTypeInternalName) {
5055
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5056
                        methodPool = methodRegistry.compile(implementationTargetFactory, classFileVersion);
1✔
5057
                        initializationHandler = new InitializationHandler.Creating(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
5058
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5059
                                auxiliaryTypeNamingStrategy,
5060
                                typeInitializer,
5061
                                classFileVersion,
5062
                                WithFullProcessing.this.classFileVersion,
5063
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5064
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5065
                                        : Implementation.Context.FrameGeneration.DISABLED);
5066
                        retainDeprecationModifiers = classFileVersion.isLessThan(ClassFileVersion.JAVA_V5);
1✔
5067
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5068
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5069
                                cv,
5070
                                implementationContext,
5071
                                typePool,
5072
                                fields,
5073
                                methods,
5074
                                writerFlags,
5075
                                readerFlags);
5076
                        cv.visit(classFileVersionNumber,
1✔
5077
                                instrumentedType.getActualModifiers((modifiers & Opcodes.ACC_SUPER) != 0 && !instrumentedType.isInterface())
1✔
5078
                                        | resolveDeprecationModifiers(modifiers)
1✔
5079
                                        // Anonymous types might not preserve their class file's final modifier via their inner class modifier.
5080
                                        | (((modifiers & Opcodes.ACC_FINAL) != 0 && instrumentedType.isAnonymousType()) ? Opcodes.ACC_FINAL : 0),
1✔
5081
                                instrumentedType.getInternalName(),
1✔
5082
                                TypeDescription.AbstractBase.RAW_TYPES
5083
                                        ? genericSignature
5084
                                        : instrumentedType.getGenericSignature(),
1✔
5085
                                instrumentedType.getSuperClass() == null
1✔
5086
                                        ? (instrumentedType.isInterface() ? TypeDescription.ForLoadedType.of(Object.class).getInternalName() : NO_REFERENCE)
1✔
5087
                                        : instrumentedType.getSuperClass().asErasure().getInternalName(),
1✔
5088
                                instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
5089
                    }
1✔
5090

5091
                    @Override
5092
                    protected void onVisitNestHost(String nestHost) {
5093
                        onNestHost();
×
5094
                    }
×
5095

5096
                    @Override
5097
                    protected void onNestHost() {
5098
                        if (!instrumentedType.isNestHost()) {
1✔
5099
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5100
                        }
5101
                    }
1✔
5102

5103
                    @Override
5104
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5105
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
5106
                            cv.visitPermittedSubclass(permittedSubclass);
×
5107
                        }
5108
                    }
×
5109

5110
                    @Override
5111
                    protected void onVisitOuterClass(String owner, @MaybeNull String name, @MaybeNull String descriptor) {
5112
                        try { // The Groovy compiler often gets this attribute wrong such that this safety just retains it.
5113
                            onOuterType();
×
5114
                        } catch (Throwable ignored) {
×
5115
                            cv.visitOuterClass(owner, name, descriptor);
×
5116
                        }
×
5117
                    }
×
5118

5119
                    @Override
5120
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "Relying on correlated type properties.")
5121
                    protected void onOuterType() {
5122
                        MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
5123
                        if (enclosingMethod != null) {
1✔
5124
                            cv.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
5125
                                    enclosingMethod.getInternalName(),
1✔
5126
                                    enclosingMethod.getDescriptor());
1✔
5127
                        } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
5128
                            cv.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
5129
                        }
5130
                    }
1✔
5131

5132
                    @Override
5133
                    protected void onAfterAttributes() {
5134
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5135
                    }
1✔
5136

5137
                    @Override
5138
                    @MaybeNull
5139
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5140
                        return annotationRetention.isEnabled()
1✔
5141
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
1✔
5142
                                : IGNORE_ANNOTATION;
×
5143
                    }
5144

5145
                    @Override
5146
                    @MaybeNull
5147
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5148
                        return annotationRetention.isEnabled()
1✔
5149
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5150
                                : IGNORE_ANNOTATION;
1✔
5151
                    }
5152

5153
                    @Override
5154
                    @MaybeNull
5155
                    protected RecordComponentVisitor onVisitRecordComponent(String name, String descriptor, @MaybeNull String genericSignature) {
5156
                        RecordComponentDescription recordComponentDescription = declarableRecordComponents.remove(name);
×
5157
                        if (recordComponentDescription != null) {
×
5158
                            RecordComponentPool.Record record = recordComponentPool.target(recordComponentDescription);
×
5159
                            if (!record.isImplicit()) {
×
5160
                                return redefine(record, genericSignature);
×
5161
                            }
5162
                        }
5163
                        return cv.visitRecordComponent(name, descriptor, genericSignature);
×
5164
                    }
5165

5166
                    /**
5167
                     * Redefines a record component using the given explicit record component pool record.
5168
                     *
5169
                     * @param record           The record component pool record to apply during visitation of the existing record.
5170
                     * @param genericSignature The record component's original generic signature which can be {@code null}.
5171
                     * @return A record component visitor for visiting the existing record component definition.
5172
                     */
5173
                    @MaybeNull
5174
                    protected RecordComponentVisitor redefine(RecordComponentPool.Record record, @MaybeNull String genericSignature) {
5175
                        RecordComponentDescription recordComponentDescription = record.getRecordComponent();
×
5176
                        RecordComponentVisitor recordComponentVisitor = cv.visitRecordComponent(recordComponentDescription.getActualName(),
×
5177
                                recordComponentDescription.getDescriptor(),
×
5178
                                TypeDescription.AbstractBase.RAW_TYPES
5179
                                        ? genericSignature
5180
                                        : recordComponentDescription.getGenericSignature());
×
5181
                        return recordComponentVisitor == null
×
5182
                                ? IGNORE_RECORD_COMPONENT
×
5183
                                : new AttributeObtainingRecordComponentVisitor(recordComponentVisitor, record);
5184
                    }
5185

5186
                    @Override
5187
                    @MaybeNull
5188
                    protected FieldVisitor onVisitField(int modifiers,
5189
                                                        String internalName,
5190
                                                        String descriptor,
5191
                                                        @MaybeNull String genericSignature,
5192
                                                        @MaybeNull Object value) {
5193
                        SignatureKey key = new SignatureKey(internalName, descriptor);
1✔
5194
                        fieldKeys.add(key);
1✔
5195
                        FieldDescription fieldDescription = declarableFields.remove(key);
1✔
5196
                        if (fieldDescription != null) {
1✔
5197
                            FieldPool.Record record = fieldPool.target(fieldDescription);
1✔
5198
                            if (!record.isImplicit()) {
1✔
5199
                                return redefine(record, value, modifiers, genericSignature);
1✔
5200
                            }
5201
                        }
5202
                        return cv.visitField(modifiers, internalName, descriptor, genericSignature, value);
1✔
5203
                    }
5204

5205
                    /**
5206
                     * Redefines a field using the given explicit field pool record and default value.
5207
                     *
5208
                     * @param record           The field pool value to apply during visitation of the existing field.
5209
                     * @param value            The default value to write onto the field which might be {@code null}.
5210
                     * @param modifiers        The original modifiers of the transformed field.
5211
                     * @param genericSignature The field's original generic signature which can be {@code null}.
5212
                     * @return A field visitor for visiting the existing field definition.
5213
                     */
5214
                    @MaybeNull
5215
                    protected FieldVisitor redefine(FieldPool.Record record, @MaybeNull Object value, int modifiers, @MaybeNull String genericSignature) {
5216
                        FieldDescription instrumentedField = record.getField();
1✔
5217
                        FieldVisitor fieldVisitor = cv.visitField(instrumentedField.getActualModifiers() | resolveDeprecationModifiers(modifiers),
1✔
5218
                                instrumentedField.getInternalName(),
1✔
5219
                                instrumentedField.getDescriptor(),
1✔
5220
                                TypeDescription.AbstractBase.RAW_TYPES
5221
                                        ? genericSignature
5222
                                        : instrumentedField.getGenericSignature(),
1✔
5223
                                record.resolveDefault(value));
1✔
5224
                        return fieldVisitor == null
1✔
5225
                                ? IGNORE_FIELD
1✔
5226
                                : new AttributeObtainingFieldVisitor(fieldVisitor, record);
5227
                    }
5228

5229
                    @Override
5230
                    @MaybeNull
5231
                    protected MethodVisitor onVisitMethod(int modifiers,
5232
                                                          String internalName,
5233
                                                          String descriptor,
5234
                                                          @MaybeNull String genericSignature,
5235
                                                          @MaybeNull String[] exceptionName) {
5236
                        if (internalName.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
5237
                            MethodVisitor methodVisitor = cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName);
1✔
5238
                            return methodVisitor == null
1✔
5239
                                    ? IGNORE_METHOD
1✔
5240
                                    : (MethodVisitor) (initializationHandler = InitializationHandler.Appending.of(implementationContext.isEnabled(),
1✔
5241
                                    methodVisitor,
5242
                                    instrumentedType,
5243
                                    methodPool,
5244
                                    annotationValueFilterFactory,
5245
                                    (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V6),
1✔
5246
                                    (readerFlags & ClassReader.EXPAND_FRAMES) != 0));
5247
                        } else {
5248
                            SignatureKey key = new SignatureKey(internalName, descriptor);
1✔
5249
                            methodsKeys.add(key);
1✔
5250
                            MethodDescription methodDescription = declarableMethods.remove(key);
1✔
5251
                            return methodDescription == null
1✔
5252
                                    ? cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName)
1✔
5253
                                    : redefine(methodDescription, (modifiers & Opcodes.ACC_ABSTRACT) != 0, modifiers, genericSignature);
1✔
5254
                        }
5255
                    }
5256

5257
                    /**
5258
                     * Redefines a given method if this is required by looking up a potential implementation from the
5259
                     * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool}.
5260
                     *
5261
                     * @param methodDescription The method being considered for redefinition.
5262
                     * @param abstractOrigin    {@code true} if the original method is abstract, i.e. there is no implementation to preserve.
5263
                     * @param modifiers         The original modifiers of the transformed method.
5264
                     * @param genericSignature  The method's original generic signature which can be {@code null}.
5265
                     * @return A method visitor which is capable of consuming the original method.
5266
                     */
5267
                    @MaybeNull
5268
                    protected MethodVisitor redefine(MethodDescription methodDescription, boolean abstractOrigin, int modifiers, @MaybeNull String genericSignature) {
5269
                        MethodPool.Record record = methodPool.target(methodDescription);
1✔
5270
                        if (!record.getSort().isDefined()) {
1✔
5271
                            return cv.visitMethod(methodDescription.getActualModifiers() | resolveDeprecationModifiers(modifiers),
×
5272
                                    methodDescription.getInternalName(),
×
5273
                                    methodDescription.getDescriptor(),
×
5274
                                    TypeDescription.AbstractBase.RAW_TYPES
5275
                                            ? genericSignature
5276
                                            : methodDescription.getGenericSignature(),
×
5277
                                    methodDescription.getExceptionTypes().asErasures().toInternalNames());
×
5278
                        }
5279
                        MethodDescription implementedMethod = record.getMethod();
1✔
5280
                        MethodVisitor methodVisitor = cv.visitMethod(ModifierContributor.Resolver
1✔
5281
                                        .of(Collections.singleton(record.getVisibility()))
1✔
5282
                                        .resolve(implementedMethod.getActualModifiers(record.getSort().isImplemented())) | resolveDeprecationModifiers(modifiers),
1✔
5283
                                implementedMethod.getInternalName(),
1✔
5284
                                implementedMethod.getDescriptor(),
1✔
5285
                                TypeDescription.AbstractBase.RAW_TYPES
5286
                                        ? genericSignature
5287
                                        : implementedMethod.getGenericSignature(),
1✔
5288
                                implementedMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
5289
                        if (methodVisitor == null) {
1✔
5290
                            return IGNORE_METHOD;
×
5291
                        } else if (abstractOrigin) {
1✔
5292
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
1✔
5293
                        } else if (methodDescription.isNative()) {
1✔
5294
                            MethodRebaseResolver.Resolution resolution = methodRebaseResolver.resolve(implementedMethod.asDefined());
×
5295
                            if (resolution.isRebased()) {
×
5296
                                MethodVisitor rebasedMethodVisitor = super.visitMethod(resolution.getResolvedMethod().getActualModifiers()
×
5297
                                                | resolveDeprecationModifiers(modifiers),
×
5298
                                        resolution.getResolvedMethod().getInternalName(),
×
5299
                                        resolution.getResolvedMethod().getDescriptor(),
×
5300
                                        TypeDescription.AbstractBase.RAW_TYPES
5301
                                                ? genericSignature
5302
                                                : implementedMethod.getGenericSignature(),
×
5303
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
×
5304
                                if (rebasedMethodVisitor != null) {
×
5305
                                    rebasedMethodVisitor.visitEnd();
×
5306
                                }
5307
                            }
5308
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
×
5309
                        } else {
5310
                            return new CodePreservingMethodVisitor(methodVisitor, record, methodRebaseResolver.resolve(implementedMethod.asDefined()));
1✔
5311
                        }
5312
                    }
5313

5314
                    @Override
5315
                    protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
5316
                        if (!internalName.equals(instrumentedType.getInternalName())) {
1✔
5317
                            TypeDescription declaredType = declaredTypes.remove(internalName);
1✔
5318
                            if (declaredType == null) {
1✔
5319
                                cv.visitInnerClass(internalName, outerName, innerName, modifiers);
1✔
5320
                            } else {
5321
                                cv.visitInnerClass(internalName,
1✔
5322
                                        // The second condition is added to retain the structure of some Java 6 compiled classes
5323
                                        declaredType.isMemberType() || outerName != null && innerName == null && declaredType.isAnonymousType()
1✔
5324
                                                ? instrumentedType.getInternalName()
1✔
5325
                                                : NO_REFERENCE,
1✔
5326
                                        declaredType.isAnonymousType()
1✔
5327
                                                ? NO_REFERENCE
1✔
5328
                                                : declaredType.getSimpleName(),
1✔
5329
                                        declaredType.getModifiers());
1✔
5330
                            }
5331
                        }
5332
                    }
1✔
5333

5334
                    @Override
5335
                    protected void onVisitNestMember(String nestMember) {
5336
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
5337
                            cv.visitNestMember(nestMember);
×
5338
                        }
5339
                    }
×
5340

5341
                    @Override
5342
                    protected void onVisitEnd() {
5343
                        for (String nestMember : nestMembers) {
1✔
5344
                            cv.visitNestMember(nestMember);
×
5345
                        }
×
5346
                        if (permittedSubclasses != null) {
1✔
5347
                            for (String permittedSubclass : permittedSubclasses) {
×
5348
                                cv.visitPermittedSubclass(permittedSubclass);
×
5349
                            }
×
5350
                        }
5351
                        TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
5352
                        if (declaringType != null) {
1✔
5353
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5354
                                    declaringType.getInternalName(),
1✔
5355
                                    instrumentedType.getSimpleName(),
1✔
5356
                                    instrumentedType.getModifiers());
1✔
5357
                        } else if (instrumentedType.isLocalType()) {
1✔
5358
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5359
                                    NO_REFERENCE,
1✔
5360
                                    instrumentedType.getSimpleName(),
1✔
5361
                                    instrumentedType.getModifiers());
1✔
5362
                        } else if (instrumentedType.isAnonymousType()) {
1✔
5363
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5364
                                    NO_REFERENCE,
1✔
5365
                                    NO_REFERENCE,
1✔
5366
                                    instrumentedType.getModifiers());
1✔
5367
                        }
5368
                        for (TypeDescription typeDescription : declaredTypes.values()) {
1✔
5369
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
5370
                                    typeDescription.isMemberType()
×
5371
                                            ? instrumentedType.getInternalName()
×
5372
                                            : NO_REFERENCE,
×
5373
                                    typeDescription.isAnonymousType()
×
5374
                                            ? NO_REFERENCE
×
5375
                                            : typeDescription.getSimpleName(),
×
5376
                                    typeDescription.getModifiers());
×
5377
                        }
×
5378
                        for (RecordComponentDescription recordComponent : declarableRecordComponents.values()) {
1✔
5379
                            recordComponentPool.target(recordComponent).apply(cv, annotationValueFilterFactory);
×
5380
                        }
×
5381
                        for (FieldDescription fieldDescription : declarableFields.values()) {
1✔
5382
                            fieldPool.target(fieldDescription).apply(new DeduplicatingClassVisitor(cv), annotationValueFilterFactory);
1✔
5383
                        }
1✔
5384
                        for (MethodDescription methodDescription : declarableMethods.values()) {
1✔
5385
                            methodPool.target(methodDescription).apply(new DeduplicatingClassVisitor(cv),
1✔
5386
                                    implementationContext,
5387
                                    annotationValueFilterFactory);
5388
                        }
1✔
5389
                        initializationHandler.complete(cv, implementationContext);
1✔
5390
                        cv.visitEnd();
1✔
5391
                    }
1✔
5392

5393
                    /**
5394
                     * Returns {@link Opcodes#ACC_DEPRECATED} if the current class file version only represents deprecated methods using modifiers
5395
                     * that are not exposed in the type description API what is true for class files before Java 5 and if the supplied modifiers indicate
5396
                     * deprecation.
5397
                     *
5398
                     * @param modifiers The original modifiers.
5399
                     * @return {@link Opcodes#ACC_DEPRECATED} if the supplied modifiers imply deprecation.
5400
                     */
5401
                    private int resolveDeprecationModifiers(int modifiers) {
5402
                        return retainDeprecationModifiers && (modifiers & Opcodes.ACC_DEPRECATED) != 0
1✔
5403
                                ? Opcodes.ACC_DEPRECATED
5404
                                : ModifierContributor.EMPTY_MASK;
5405
                    }
5406

5407
                    /**
5408
                     * A class visitor that deduplicates fields and methods, mostly when access bridge methods are
5409
                     * previously declared, but incomplete.
5410
                     */
5411
                    protected class DeduplicatingClassVisitor extends ClassVisitor {
5412

5413
                        /**
5414
                         * Creates a new method deduplicating class visitor.
5415
                         *
5416
                         * @param classVisitor The class visitor to delegate to.
5417
                         */
5418
                        protected DeduplicatingClassVisitor(ClassVisitor classVisitor) {
1✔
5419
                            super(OpenedClassReader.ASM_API, classVisitor);
1✔
5420
                        }
1✔
5421

5422
                        @Override
5423
                        @MaybeNull
5424
                        public FieldVisitor visitField(int access,
5425
                                                       String internalName,
5426
                                                       String descriptor,
5427
                                                       @MaybeNull String signature,
5428
                                                       @MaybeNull Object value) {
5429
                            if (fieldKeys.contains(new SignatureKey(internalName, descriptor))) {
1✔
5430
                                throw new IllegalStateException("Field already defined: " + internalName + descriptor);
×
5431
                            }
5432
                            return super.visitField(access, internalName, descriptor, signature, value);
1✔
5433
                        }
5434

5435
                        @Override
5436
                        @MaybeNull
5437
                        public MethodVisitor visitMethod(int access,
5438
                                                         String internalName,
5439
                                                         String descriptor,
5440
                                                         @MaybeNull String signature,
5441
                                                         @MaybeNull String[] exception) {
5442
                            if (methodsKeys.contains(new SignatureKey(internalName, descriptor))) {
1✔
5443
                                if ((access & Opcodes.ACC_BRIDGE) != 0) {
×
5444
                                    return null;
×
5445
                                } else {
5446
                                    throw new IllegalStateException("Method already defined: " + internalName + descriptor);
×
5447
                                }
5448
                            }
5449
                            return super.visitMethod(access, internalName, descriptor, signature, exception);
1✔
5450
                        }
5451
                    }
5452

5453
                    /**
5454
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5455
                     * class file but that discards all code.
5456
                     */
5457
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5458

5459
                        /**
5460
                         * The field pool record to apply onto the field visitor.
5461
                         */
5462
                        private final FieldPool.Record record;
5463

5464
                        /**
5465
                         * Creates a new attribute obtaining field visitor.
5466
                         *
5467
                         * @param fieldVisitor The field visitor to delegate to.
5468
                         * @param record       The field pool record to apply onto the field visitor.
5469
                         */
5470
                        protected AttributeObtainingFieldVisitor(FieldVisitor fieldVisitor, FieldPool.Record record) {
1✔
5471
                            super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
5472
                            this.record = record;
1✔
5473
                        }
1✔
5474

5475
                        @Override
5476
                        @MaybeNull
5477
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5478
                            return annotationRetention.isEnabled()
×
5479
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5480
                                    : IGNORE_ANNOTATION;
×
5481
                        }
5482

5483
                        @Override
5484
                        @MaybeNull
5485
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5486
                            return annotationRetention.isEnabled()
1✔
5487
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5488
                                    : IGNORE_ANNOTATION;
1✔
5489
                        }
5490

5491
                        @Override
5492
                        public void visitEnd() {
5493
                            record.apply(fv, annotationValueFilterFactory);
1✔
5494
                            super.visitEnd();
1✔
5495
                        }
1✔
5496
                    }
5497

5498
                    /**
5499
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5500
                     * in the class file but discards all code.
5501
                     */
5502
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5503

5504
                        /**
5505
                         * The record component pool record to apply onto the record component visitor.
5506
                         */
5507
                        private final RecordComponentPool.Record record;
5508

5509
                        /**
5510
                         * Creates a new attribute obtaining record component visitor.
5511
                         *
5512
                         * @param recordComponentVisitor The record component visitor to delegate to.
5513
                         * @param record                 The record component pool record to apply onto the record component visitor.
5514
                         */
5515
                        protected AttributeObtainingRecordComponentVisitor(RecordComponentVisitor recordComponentVisitor, RecordComponentPool.Record record) {
×
5516
                            super(OpenedClassReader.ASM_API, recordComponentVisitor);
×
5517
                            this.record = record;
×
5518
                        }
×
5519

5520
                        @Override
5521
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5522
                            return annotationRetention.isEnabled()
×
5523
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5524
                                    : IGNORE_ANNOTATION;
×
5525
                        }
5526

5527
                        @Override
5528
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5529
                            return annotationRetention.isEnabled()
×
5530
                                    ? super.visitAnnotation(descriptor, visible)
×
5531
                                    : IGNORE_ANNOTATION;
×
5532
                        }
5533

5534
                        @Override
5535
                        public void visitEnd() {
5536
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5537
                            super.visitEnd();
×
5538
                        }
×
5539
                    }
5540

5541
                    /**
5542
                     * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5543
                     * method while copying all attributes and annotations to the actual method.
5544
                     */
5545
                    protected class CodePreservingMethodVisitor extends MethodVisitor {
5546

5547
                        /**
5548
                         * The method visitor of the actual method.
5549
                         */
5550
                        private final MethodVisitor actualMethodVisitor;
5551

5552
                        /**
5553
                         * The method pool entry to apply.
5554
                         */
5555
                        private final MethodPool.Record record;
5556

5557
                        /**
5558
                         * The resolution of a potential rebased method.
5559
                         */
5560
                        private final MethodRebaseResolver.Resolution resolution;
5561

5562
                        /**
5563
                         * Creates a new code preserving method visitor.
5564
                         *
5565
                         * @param actualMethodVisitor The method visitor of the actual method.
5566
                         * @param record              The method pool entry to apply.
5567
                         * @param resolution          The resolution of the method rebase resolver in use.
5568
                         */
5569
                        protected CodePreservingMethodVisitor(MethodVisitor actualMethodVisitor,
5570
                                                              MethodPool.Record record,
5571
                                                              MethodRebaseResolver.Resolution resolution) {
1✔
5572
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5573
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5574
                            this.record = record;
1✔
5575
                            this.resolution = resolution;
1✔
5576
                            record.applyHead(actualMethodVisitor);
1✔
5577
                        }
1✔
5578

5579
                        @Override
5580
                        @MaybeNull
5581
                        public AnnotationVisitor visitAnnotationDefault() {
5582
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5583
                        }
5584

5585
                        @Override
5586
                        @MaybeNull
5587
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5588
                            return annotationRetention.isEnabled()
×
5589
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5590
                                    : IGNORE_ANNOTATION;
×
5591
                        }
5592

5593
                        @Override
5594
                        @MaybeNull
5595
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5596
                            return annotationRetention.isEnabled()
1✔
5597
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5598
                                    : IGNORE_ANNOTATION;
1✔
5599
                        }
5600

5601
                        @Override
5602
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5603
                            if (annotationRetention.isEnabled()) {
1✔
5604
                                super.visitAnnotableParameterCount(count, visible);
1✔
5605
                            }
5606
                        }
1✔
5607

5608
                        @Override
5609
                        @MaybeNull
5610
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5611
                            return annotationRetention.isEnabled()
1✔
5612
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
1✔
5613
                                    : IGNORE_ANNOTATION;
1✔
5614
                        }
5615

5616
                        @Override
5617
                        public void visitCode() {
5618
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5619
                            actualMethodVisitor.visitEnd();
1✔
5620
                            if (resolution.isRebased()) {
1✔
5621
                                mv = cv.visitMethod(resolution.getResolvedMethod().getActualModifiers(),
1✔
5622
                                        resolution.getResolvedMethod().getInternalName(),
1✔
5623
                                        resolution.getResolvedMethod().getDescriptor(),
1✔
5624
                                        resolution.getResolvedMethod().getGenericSignature(),
1✔
5625
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
5626
                                super.visitCode();
1✔
5627
                                if (!resolution.getAppendedParameters().isEmpty() && implementationContext.getFrameGeneration().isActive()) {
1✔
5628
                                    if (implementationContext.getFrameGeneration() == Implementation.Context.FrameGeneration.GENERATE && resolution.getAppendedParameters().size() < 4) {
1✔
5629
                                        super.visitFrame(Opcodes.F_CHOP, resolution.getAppendedParameters().size(), EMPTY, EMPTY.length, EMPTY);
1✔
5630
                                    } else {
5631
                                        Object[] frame = new Object[resolution.getResolvedMethod().getParameters().size()
1✔
5632
                                                - resolution.getAppendedParameters().size()
1✔
5633
                                                + 1];
5634
                                        frame[0] = Opcodes.UNINITIALIZED_THIS;
1✔
5635
                                        for (int index = 1; index < frame.length; index++) {
1✔
5636
                                            TypeDefinition typeDefinition = resolution.getResolvedMethod()
1✔
5637
                                                    .getParameters()
1✔
5638
                                                    .get(index - 1)
1✔
5639
                                                    .getType();
1✔
5640
                                            if (typeDefinition.represents(boolean.class)
1✔
5641
                                                    || typeDefinition.represents(byte.class)
1✔
5642
                                                    || typeDefinition.represents(short.class)
1✔
5643
                                                    || typeDefinition.represents(char.class)
1✔
5644
                                                    || typeDefinition.represents(int.class)) {
1✔
5645
                                                frame[index] = Opcodes.INTEGER;
×
5646
                                            } else if (typeDefinition.represents(long.class)) {
1✔
5647
                                                frame[index] = Opcodes.LONG;
×
5648
                                            } else if (typeDefinition.represents(float.class)) {
1✔
5649
                                                frame[index] = Opcodes.FLOAT;
×
5650
                                            } else if (typeDefinition.represents(double.class)) {
1✔
5651
                                                frame[index] = Opcodes.DOUBLE;
×
5652
                                            } else {
5653
                                                frame[index] = typeDefinition.asErasure().getInternalName();
1✔
5654
                                            }
5655
                                        }
5656
                                        super.visitFrame((readerFlags & ClassReader.EXPAND_FRAMES) == 0
1✔
5657
                                                ? Opcodes.F_FULL
5658
                                                : Opcodes.F_NEW, frame.length, frame, EMPTY.length, EMPTY);
1✔
5659
                                    }
5660
                                    super.visitInsn(Opcodes.NOP);
1✔
5661
                                }
5662
                            } else {
5663
                                mv = IGNORE_METHOD;
1✔
5664
                                super.visitCode();
1✔
5665
                            }
5666
                        }
1✔
5667

5668
                        @Override
5669
                        public void visitMaxs(int stackSize, int localVariableLength) {
5670
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5671
                        }
1✔
5672
                    }
5673

5674
                    /**
5675
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5676
                     * class file but that discards all code.
5677
                     */
5678
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5679

5680
                        /**
5681
                         * The method visitor to which the actual method is to be written to.
5682
                         */
5683
                        private final MethodVisitor actualMethodVisitor;
5684

5685
                        /**
5686
                         * The method pool entry to apply.
5687
                         */
5688
                        private final MethodPool.Record record;
5689

5690
                        /**
5691
                         * Creates a new attribute obtaining method visitor.
5692
                         *
5693
                         * @param actualMethodVisitor The method visitor of the actual method.
5694
                         * @param record              The method pool entry to apply.
5695
                         */
5696
                        protected AttributeObtainingMethodVisitor(MethodVisitor actualMethodVisitor, MethodPool.Record record) {
1✔
5697
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5698
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5699
                            this.record = record;
1✔
5700
                            record.applyHead(actualMethodVisitor);
1✔
5701
                        }
1✔
5702

5703
                        @Override
5704
                        @MaybeNull
5705
                        public AnnotationVisitor visitAnnotationDefault() {
5706
                            return IGNORE_ANNOTATION;
×
5707
                        }
5708

5709
                        @Override
5710
                        @MaybeNull
5711
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5712
                            return annotationRetention.isEnabled()
×
5713
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5714
                                    : IGNORE_ANNOTATION;
×
5715
                        }
5716

5717
                        @Override
5718
                        @MaybeNull
5719
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5720
                            return annotationRetention.isEnabled()
×
5721
                                    ? super.visitAnnotation(descriptor, visible)
×
5722
                                    : IGNORE_ANNOTATION;
×
5723
                        }
5724

5725
                        @Override
5726
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5727
                            if (annotationRetention.isEnabled()) {
×
5728
                                super.visitAnnotableParameterCount(count, visible);
×
5729
                            }
5730
                        }
×
5731

5732
                        @Override
5733
                        @MaybeNull
5734
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5735
                            return annotationRetention.isEnabled()
×
5736
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
5737
                                    : IGNORE_ANNOTATION;
×
5738
                        }
5739

5740
                        @Override
5741
                        public void visitCode() {
5742
                            mv = IGNORE_METHOD;
×
5743
                        }
×
5744

5745
                        @Override
5746
                        public void visitEnd() {
5747
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5748
                            actualMethodVisitor.visitEnd();
1✔
5749
                        }
1✔
5750
                    }
5751
                }
5752
            }
5753

5754
            /**
5755
             * A default type writer that only applies a type decoration.
5756
             *
5757
             * @param <V> The best known loaded type for the dynamically created type.
5758
             */
5759
            protected static class WithDecorationOnly<V> extends ForInlining<V> {
5760

5761
                /**
5762
                 * Creates a new inlining type writer that only applies a decoration.
5763
                 *
5764
                 * @param instrumentedType             The instrumented type to be created.
5765
                 * @param classFileVersion             The class file specified by the user.
5766
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
5767
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
5768
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5769
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5770
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5771
                 * @param annotationRetention          The annotation retention to apply.
5772
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5773
                 * @param implementationContextFactory The implementation context factory to apply.
5774
                 * @param typeValidation               Determines if a type should be explicitly validated.
5775
                 * @param classReaderFactory           The class reader factory to use.
5776
                 * @param classWriterFactory           The class writer factory to use.
5777
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
5778
                 * @param classFileLocator             The class file locator for locating the original type's class file.
5779
                 */
5780
                protected WithDecorationOnly(TypeDescription instrumentedType,
5781
                                             ClassFileVersion classFileVersion,
5782
                                             List<? extends DynamicType> auxiliaryTypes,
5783
                                             MethodList<?> methods,
5784
                                             TypeAttributeAppender typeAttributeAppender,
5785
                                             AsmVisitorWrapper asmVisitorWrapper,
5786
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
5787
                                             AnnotationRetention annotationRetention,
5788
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5789
                                             Implementation.Context.Factory implementationContextFactory,
5790
                                             TypeValidation typeValidation,
5791
                                             AsmClassReader.Factory classReaderFactory,
5792
                                             AsmClassWriter.Factory classWriterFactory,
5793
                                             TypePool typePool,
5794
                                             ClassFileLocator classFileLocator) {
5795
                    super(instrumentedType,
1✔
5796
                            classFileVersion,
5797
                            FieldPool.Disabled.INSTANCE,
5798
                            RecordComponentPool.Disabled.INSTANCE,
5799
                            auxiliaryTypes,
5800
                            new LazyFieldList(instrumentedType),
5801
                            methods,
5802
                            new MethodList.Empty<MethodDescription>(),
5803
                            new RecordComponentList.Empty<RecordComponentDescription.InDefinedShape>(),
5804
                            LoadedTypeInitializer.NoOp.INSTANCE,
5805
                            TypeInitializer.None.INSTANCE,
5806
                            typeAttributeAppender,
5807
                            asmVisitorWrapper,
5808
                            annotationValueFilterFactory,
5809
                            annotationRetention,
5810
                            auxiliaryTypeNamingStrategy,
5811
                            implementationContextFactory,
5812
                            typeValidation,
5813
                            classReaderFactory,
5814
                            classWriterFactory,
5815
                            typePool,
5816
                            instrumentedType,
5817
                            classFileLocator);
5818
                }
1✔
5819

5820
                /**
5821
                 * {@inheritDoc}
5822
                 */
5823
                protected ClassVisitor writeTo(ClassVisitor classVisitor,
5824
                                               TypeInitializer typeInitializer,
5825
                                               ContextRegistry contextRegistry,
5826
                                               int writerFlags,
5827
                                               int readerFlags) {
5828
                    if (typeInitializer.isDefined()) {
1✔
5829
                        throw new UnsupportedOperationException("Cannot apply a type initializer for a decoration");
×
5830
                    }
5831
                    return new DecorationClassVisitor(classVisitor, contextRegistry, writerFlags, readerFlags);
1✔
5832
                }
5833

5834
                /**
5835
                 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5836
                 */
5837
                protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5838

5839
                    /**
5840
                     * The instrumented type.
5841
                     */
5842
                    private final TypeDescription instrumentedType;
5843

5844
                    /**
5845
                     * Creates a lazy field list.
5846
                     *
5847
                     * @param instrumentedType The instrumented type.
5848
                     */
5849
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
5850
                        this.instrumentedType = instrumentedType;
1✔
5851
                    }
1✔
5852

5853
                    /**
5854
                     * {@inheritDoc}
5855
                     */
5856
                    public FieldDescription.InDefinedShape get(int index) {
5857
                        return instrumentedType.getDeclaredFields().get(index);
×
5858
                    }
5859

5860
                    /**
5861
                     * {@inheritDoc}
5862
                     */
5863
                    public int size() {
5864
                        return instrumentedType.getDeclaredFields().size();
×
5865
                    }
5866
                }
5867

5868
                /**
5869
                 * A class visitor that decorates an existing type.
5870
                 */
5871
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
5872
                protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
5873

5874
                    /**
5875
                     * A context registry to register the lazily created implementation context to.
5876
                     */
5877
                    private final ContextRegistry contextRegistry;
5878

5879
                    /**
5880
                     * The writer flags being used.
5881
                     */
5882
                    private final int writerFlags;
5883

5884
                    /**
5885
                     * The reader flags being used.
5886
                     */
5887
                    private final int readerFlags;
5888

5889
                    /**
5890
                     * The implementation context to use or {@code null} if the context is not yet initialized.
5891
                     */
5892
                    @UnknownNull
5893
                    private Implementation.Context.ExtractableView implementationContext;
5894

5895
                    /**
5896
                     * Creates a class visitor which is capable of decorating an existent class on the fly.
5897
                     *
5898
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
5899
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
5900
                     * @param writerFlags     The writer flags being used.
5901
                     * @param readerFlags     The reader flags being used.
5902
                     */
5903
                    protected DecorationClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
1✔
5904
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
5905
                        this.contextRegistry = contextRegistry;
1✔
5906
                        this.writerFlags = writerFlags;
1✔
5907
                        this.readerFlags = readerFlags;
1✔
5908
                    }
1✔
5909

5910
                    @Override
5911
                    public void visit(int classFileVersionNumber,
5912
                                      int modifiers,
5913
                                      String internalName,
5914
                                      String genericSignature,
5915
                                      String superClassInternalName,
5916
                                      String[] interfaceTypeInternalName) {
5917
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5918
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5919
                                auxiliaryTypeNamingStrategy,
5920
                                typeInitializer,
5921
                                classFileVersion,
5922
                                WithDecorationOnly.this.classFileVersion,
5923
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5924
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5925
                                        : Implementation.Context.FrameGeneration.DISABLED);
5926
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5927
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5928
                                cv,
5929
                                implementationContext,
5930
                                typePool,
5931
                                fields,
5932
                                methods,
5933
                                writerFlags,
5934
                                readerFlags);
5935
                        cv.visit(classFileVersionNumber, modifiers, internalName, genericSignature, superClassInternalName, interfaceTypeInternalName);
1✔
5936
                    }
1✔
5937

5938
                    @Override
5939
                    @MaybeNull
5940
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5941
                        return annotationRetention.isEnabled()
×
5942
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5943
                                : IGNORE_ANNOTATION;
×
5944
                    }
5945

5946
                    @Override
5947
                    @MaybeNull
5948
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5949
                        return annotationRetention.isEnabled()
1✔
5950
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5951
                                : IGNORE_ANNOTATION;
1✔
5952
                    }
5953

5954
                    @Override
5955
                    protected void onAfterAttributes() {
5956
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5957
                    }
1✔
5958

5959
                    @Override
5960
                    protected void onVisitEnd() {
5961
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
5962
                        cv.visitEnd();
1✔
5963
                    }
1✔
5964

5965
                    /**
5966
                     * {@inheritDoc}
5967
                     */
5968
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
5969
                        /* do nothing */
5970
                    }
1✔
5971
                }
5972
            }
5973
        }
5974

5975
        /**
5976
         * A type writer that creates a class file that is not based upon another, existing class.
5977
         *
5978
         * @param <U> The best known loaded type for the dynamically created type.
5979
         */
5980
        @HashCodeAndEqualsPlugin.Enhance
5981
        public static class ForCreation<U> extends Default<U> {
5982

5983
            /**
5984
             * The method pool to use.
5985
             */
5986
            private final MethodPool methodPool;
5987

5988
            /**
5989
             * Creates a new default type writer for creating a new type that is not based on an existing class file.
5990
             *
5991
             * @param instrumentedType             The instrumented type to be created.
5992
             * @param classFileVersion             The class file version to write the instrumented type in and to apply when creating auxiliary types.
5993
             * @param fieldPool                    The field pool to use.
5994
             * @param methodPool                   The method pool to use.
5995
             * @param recordComponentPool          The record component pool to use.
5996
             * @param auxiliaryTypes               A list of auxiliary types to add to the created type.
5997
             * @param fields                       The instrumented type's declared fields.
5998
             * @param methods                      The instrumented type's declared and virtually inherited methods.
5999
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
6000
             * @param recordComponents             The instrumented type's record components.
6001
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
6002
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
6003
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
6004
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
6005
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
6006
             * @param annotationRetention          The annotation retention to apply.
6007
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
6008
             * @param implementationContextFactory The implementation context factory to apply.
6009
             * @param typeValidation               Determines if a type should be explicitly validated.
6010
             * @param classReaderFactory           The class reader factory to use.
6011
             * @param classWriterFactory           The class writer factory to use.
6012
             * @param typePool                     The type pool to use for computing stack map frames, if required.
6013
             */
6014
            protected ForCreation(TypeDescription instrumentedType,
6015
                                  ClassFileVersion classFileVersion,
6016
                                  FieldPool fieldPool,
6017
                                  MethodPool methodPool,
6018
                                  RecordComponentPool recordComponentPool,
6019
                                  List<? extends DynamicType> auxiliaryTypes,
6020
                                  FieldList<FieldDescription.InDefinedShape> fields,
6021
                                  MethodList<?> methods,
6022
                                  MethodList<?> instrumentedMethods,
6023
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
6024
                                  LoadedTypeInitializer loadedTypeInitializer,
6025
                                  TypeInitializer typeInitializer,
6026
                                  TypeAttributeAppender typeAttributeAppender,
6027
                                  AsmVisitorWrapper asmVisitorWrapper,
6028
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
6029
                                  AnnotationRetention annotationRetention,
6030
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
6031
                                  Implementation.Context.Factory implementationContextFactory,
6032
                                  TypeValidation typeValidation,
6033
                                  AsmClassReader.Factory classReaderFactory,
6034
                                  AsmClassWriter.Factory classWriterFactory,
6035
                                  TypePool typePool) {
6036
                super(instrumentedType,
1✔
6037
                        classFileVersion,
6038
                        fieldPool,
6039
                        recordComponentPool,
6040
                        auxiliaryTypes,
6041
                        fields,
6042
                        methods,
6043
                        instrumentedMethods,
6044
                        recordComponents,
6045
                        loadedTypeInitializer,
6046
                        typeInitializer,
6047
                        typeAttributeAppender,
6048
                        asmVisitorWrapper,
6049
                        annotationValueFilterFactory,
6050
                        annotationRetention,
6051
                        auxiliaryTypeNamingStrategy,
6052
                        implementationContextFactory,
6053
                        typeValidation,
6054
                        classReaderFactory,
6055
                        classWriterFactory,
6056
                        typePool);
6057
                this.methodPool = methodPool;
1✔
6058
            }
1✔
6059

6060
            /**
6061
             * {@inheritDoc}
6062
             */
6063
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
6064
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6065
                        auxiliaryTypeNamingStrategy,
6066
                        typeInitializer,
6067
                        classFileVersion,
6068
                        classFileVersion,
6069
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6070
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6071
                                : Implementation.Context.FrameGeneration.DISABLED);
6072
                return new ImplementationContextClassVisitor(new CreationClassVisitor(asmVisitorWrapper.wrap(instrumentedType,
1✔
6073
                        ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
6074
                        implementationContext,
6075
                        typePool,
6076
                        fields,
6077
                        methods,
6078
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
6079
                        asmVisitorWrapper.mergeReader(readerFlags)), implementationContext), implementationContext);
1✔
6080
            }
6081

6082
            @Override
6083
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
6084
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
6085
                int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS), readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
6086
                AsmClassWriter classWriter = classWriterFactory.make(writerFlags, typePool);
1✔
6087
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6088
                        auxiliaryTypeNamingStrategy,
6089
                        typeInitializer,
6090
                        classFileVersion,
6091
                        classFileVersion,
6092
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6093
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6094
                                : Implementation.Context.FrameGeneration.DISABLED);
6095
                ClassVisitor classVisitor = asmVisitorWrapper.wrap(instrumentedType,
1✔
6096
                        ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
6097
                        implementationContext,
6098
                        typePool,
6099
                        fields,
6100
                        methods,
6101
                        writerFlags,
6102
                        readerFlags);
6103
                classVisitor.visit(classFileVersion.getMinorMajorVersion(),
1✔
6104
                        instrumentedType.getActualModifiers(!instrumentedType.isInterface()),
1✔
6105
                        instrumentedType.getInternalName(),
1✔
6106
                        instrumentedType.getGenericSignature(),
1✔
6107
                        (instrumentedType.getSuperClass() == null
1✔
6108
                                ? TypeDescription.ForLoadedType.of(Object.class)
1✔
6109
                                : instrumentedType.getSuperClass().asErasure()).getInternalName(),
1✔
6110
                        instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
6111
                if (!instrumentedType.isNestHost()) {
1✔
6112
                    classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
6113
                }
6114
                MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
6115
                if (enclosingMethod != null) {
1✔
6116
                    classVisitor.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
6117
                            enclosingMethod.getInternalName(),
1✔
6118
                            enclosingMethod.getDescriptor());
1✔
6119
                } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
6120
                    classVisitor.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
6121
                }
6122
                typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6123
                if (instrumentedType.isNestHost()) {
1✔
6124
                    for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
6125
                        classVisitor.visitNestMember(typeDescription.getInternalName());
×
6126
                    }
×
6127
                }
6128
                for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
1✔
6129
                    classVisitor.visitPermittedSubclass(typeDescription.getInternalName());
×
6130
                }
×
6131
                TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
6132
                if (declaringType != null) {
1✔
6133
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6134
                            declaringType.getInternalName(),
1✔
6135
                            instrumentedType.getSimpleName(),
1✔
6136
                            instrumentedType.getModifiers());
1✔
6137
                } else if (instrumentedType.isLocalType()) {
1✔
6138
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6139
                            NO_REFERENCE,
1✔
6140
                            instrumentedType.getSimpleName(),
1✔
6141
                            instrumentedType.getModifiers());
1✔
6142
                } else if (instrumentedType.isAnonymousType()) {
1✔
6143
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6144
                            NO_REFERENCE,
1✔
6145
                            NO_REFERENCE,
1✔
6146
                            instrumentedType.getModifiers());
1✔
6147
                }
6148
                for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6149
                    classVisitor.visitInnerClass(typeDescription.getInternalName(),
1✔
6150
                            typeDescription.isMemberType()
1✔
6151
                                    ? instrumentedType.getInternalName()
1✔
6152
                                    : NO_REFERENCE,
1✔
6153
                            typeDescription.isAnonymousType()
1✔
6154
                                    ? NO_REFERENCE
1✔
6155
                                    : typeDescription.getSimpleName(),
1✔
6156
                            typeDescription.getModifiers());
1✔
6157
                }
1✔
6158
                for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
6159
                    recordComponentPool.target(recordComponentDescription).apply(classVisitor, annotationValueFilterFactory);
×
6160
                }
×
6161
                for (FieldDescription fieldDescription : fields) {
1✔
6162
                    fieldPool.target(fieldDescription).apply(classVisitor, annotationValueFilterFactory);
1✔
6163
                }
1✔
6164
                for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6165
                    methodPool.target(methodDescription).apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
6166
                }
1✔
6167
                implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6168
                        methodPool,
6169
                        annotationValueFilterFactory), classVisitor, annotationValueFilterFactory);
6170
                classVisitor.visitEnd();
1✔
6171
                return new UnresolvedType(classWriter.getBinaryRepresentation(), implementationContext.getAuxiliaryTypes());
1✔
6172
            }
6173

6174
            /**
6175
             * A class visitor that applies the subclass creation as a wrapper.
6176
             */
6177
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6178

6179
                /**
6180
                 * The implementation context to apply.
6181
                 */
6182
                private final Implementation.Context.ExtractableView implementationContext;
6183

6184
                /**
6185
                 * The declared types that have been visited.
6186
                 */
6187
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6188

6189
                /**
6190
                 * The signatures of all fields that were explicitly visited.
6191
                 */
6192
                private final Set<SignatureKey> visitedFields = new HashSet<SignatureKey>();
1✔
6193

6194
                /**
6195
                 * The signature of all methods that were explicitly visited.
6196
                 */
6197
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6198

6199
                /**
6200
                 * Creates a new wrapper visitor.
6201
                 *
6202
                 * @param classVisitor          The class visitor being wrapped.
6203
                 * @param implementationContext The implementation context to apply.
6204
                 */
6205
                protected CreationClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6206
                    super(OpenedClassReader.ASM_API, classVisitor);
1✔
6207
                    this.implementationContext = implementationContext;
1✔
6208
                }
1✔
6209

6210
                @Override
6211
                protected void onAfterAttributes() {
6212
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6213
                }
1✔
6214

6215
                @Override
6216
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6217
                    declaredTypes.add(internalName);
×
6218
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
6219
                }
×
6220

6221
                @Override
6222
                @MaybeNull
6223
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6224
                    visitedFields.add(new SignatureKey(name, descriptor));
×
6225
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6226
                }
6227

6228
                @Override
6229
                @MaybeNull
6230
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
6231
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
6232
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6233
                }
6234

6235
                @Override
6236
                protected void onVisitEnd() {
6237
                    for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6238
                        if (!declaredTypes.contains(typeDescription.getInternalName())) {
×
6239
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
6240
                                    typeDescription.isMemberType()
×
6241
                                            ? instrumentedType.getInternalName()
×
6242
                                            : NO_REFERENCE,
×
6243
                                    typeDescription.isAnonymousType()
×
6244
                                            ? NO_REFERENCE
×
6245
                                            : typeDescription.getSimpleName(),
×
6246
                                    typeDescription.getModifiers());
×
6247
                        }
6248
                    }
×
6249
                    for (FieldDescription fieldDescription : fields) {
1✔
6250
                        if (!visitedFields.contains(new SignatureKey(fieldDescription.getName(), fieldDescription.getDescriptor()))) {
×
6251
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
×
6252
                        }
6253
                    }
×
6254
                    for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6255
                        if (!visitedMethods.contains(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()))) {
1✔
6256
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
6257
                        }
6258
                    }
1✔
6259
                    implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6260
                            methodPool,
1✔
6261
                            annotationValueFilterFactory), cv, annotationValueFilterFactory);
6262
                    super.onVisitEnd();
1✔
6263
                }
1✔
6264
            }
6265

6266
            /**
6267
             * A context class visitor based on an {@link Implementation.Context}.
6268
             */
6269
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6270

6271
                /**
6272
                 * The implementation context to use.
6273
                 */
6274
                private final Implementation.Context.ExtractableView implementationContext;
6275

6276
                /**
6277
                 * Creates a context class loader based on an {@link Implementation.Context}.
6278
                 *
6279
                 * @param classVisitor          The class visitor to delegate to.
6280
                 * @param implementationContext The implementation context to use.
6281
                 */
6282
                protected ImplementationContextClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6283
                    super(classVisitor);
1✔
6284
                    this.implementationContext = implementationContext;
1✔
6285
                }
1✔
6286

6287
                @Override
6288
                public List<DynamicType> getAuxiliaryTypes() {
6289
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6290
                }
6291

6292
                @Override
6293
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6294
                    return loadedTypeInitializer;
1✔
6295
                }
6296
            }
6297
        }
6298

6299
        /**
6300
         * An action to write a class file to the dumping location.
6301
         */
6302
        @HashCodeAndEqualsPlugin.Enhance
6303
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6304

6305
            /**
6306
             * Indicates that nothing is returned from this action.
6307
             */
6308
            @AlwaysNull
6309
            private static final Void NOTHING = null;
1✔
6310

6311
            /**
6312
             * The target folder for writing the class file to.
6313
             */
6314
            private final String target;
6315

6316
            /**
6317
             * The instrumented type.
6318
             */
6319
            private final TypeDescription instrumentedType;
6320

6321
            /**
6322
             * {@code true} if the dumped class file is an input to a class transformation.
6323
             */
6324
            private final boolean original;
6325

6326
            /**
6327
             * The suffix to append to the dumped class file.
6328
             */
6329
            private final long suffix;
6330

6331
            /**
6332
             * The type's binary representation.
6333
             */
6334
            private final byte[] binaryRepresentation;
6335

6336
            /**
6337
             * Creates a new class dump action.
6338
             *
6339
             * @param target               The target folder for writing the class file to.
6340
             * @param instrumentedType     The instrumented type.
6341
             * @param original             {@code true} if the dumped class file is an input to a class transformation.
6342
             * @param suffix               The suffix to append to the dumped class file.
6343
             * @param binaryRepresentation The type's binary representation.
6344
             */
6345
            protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
1✔
6346
                this.target = target;
1✔
6347
                this.instrumentedType = instrumentedType;
1✔
6348
                this.original = original;
1✔
6349
                this.suffix = suffix;
1✔
6350
                this.binaryRepresentation = binaryRepresentation;
1✔
6351
            }
1✔
6352

6353
            /**
6354
             * {@inheritDoc}
6355
             */
6356
            public Void run() throws Exception {
6357
                OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
1✔
6358
                        + (original ? "-original." : ".")
6359
                        + suffix
6360
                        + ".class"));
6361
                try {
6362
                    outputStream.write(binaryRepresentation);
1✔
6363
                    return NOTHING;
1✔
6364
                } finally {
6365
                    outputStream.close();
1✔
6366
                }
6367
            }
6368

6369
            /**
6370
             * A dispatcher for dumping class files to the file system.
6371
             */
6372
            protected interface Dispatcher {
6373

6374
                /**
6375
                 * Dumps a class file to the file system.
6376
                 *
6377
                 * @param instrumentedType     The type to dump.
6378
                 * @param original             {@code true} if the class file is in its original state.
6379
                 * @param binaryRepresentation The class file's binary representation.
6380
                 */
6381
                void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
6382

6383
                /**
6384
                 * A disabled dispatcher that does not dump any class files.
6385
                 */
6386
                enum Disabled implements Dispatcher {
1✔
6387

6388
                    /**
6389
                     * The singleton instance.
6390
                     */
6391
                    INSTANCE;
1✔
6392

6393
                    /**
6394
                     * {@inheritDoc}
6395
                     */
6396
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6397
                        /* do nothing */
6398
                    }
1✔
6399
                }
6400

6401
                /**
6402
                 * An enabled dispatcher that dumps class files to a given folder.
6403
                 */
6404
                @HashCodeAndEqualsPlugin.Enhance
6405
                class Enabled implements Dispatcher {
6406

6407
                    /**
6408
                     * The folder to write class files to.
6409
                     */
6410
                    private final String folder;
6411

6412
                    /**
6413
                     * The timestamp to append.
6414
                     */
6415
                    private final long timestamp;
6416

6417
                    /**
6418
                     * Creates a new dispatcher for dumping class files.
6419
                     *
6420
                     * @param folder    The folder to write class files to.
6421
                     * @param timestamp The timestamp to append.
6422
                     */
6423
                    protected Enabled(String folder, long timestamp) {
1✔
6424
                        this.folder = folder;
1✔
6425
                        this.timestamp = timestamp;
1✔
6426
                    }
1✔
6427

6428
                    /**
6429
                     * {@inheritDoc}
6430
                     */
6431
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6432
                        try {
6433
                            doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
1✔
6434
                        } catch (Exception exception) {
×
6435
                            exception.printStackTrace();
×
6436
                        }
1✔
6437
                    }
1✔
6438
                }
6439
            }
6440
        }
6441
    }
6442
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc