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

raphw / byte-buddy / #809

02 Nov 2025 10:24PM UTC coverage: 84.035% (-0.6%) from 84.614%
#809

push

raphw
Clean up code.

5 of 7 new or added lines in 4 files covered. (71.43%)

958 existing lines in 10 files now uncovered.

29803 of 35465 relevant lines covered (84.03%)

0.84 hits per line

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

76.24
/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.module.ModuleDescription;
34
import net.bytebuddy.description.type.PackageDescription;
35
import net.bytebuddy.description.type.RecordComponentDescription;
36
import net.bytebuddy.description.type.RecordComponentList;
37
import net.bytebuddy.description.type.TypeDefinition;
38
import net.bytebuddy.description.type.TypeDescription;
39
import net.bytebuddy.description.type.TypeList;
40
import net.bytebuddy.dynamic.ClassFileLocator;
41
import net.bytebuddy.dynamic.DynamicType;
42
import net.bytebuddy.dynamic.TypeResolutionStrategy;
43
import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
44
import net.bytebuddy.dynamic.scaffold.inline.RebaseImplementationTarget;
45
import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget;
46
import net.bytebuddy.implementation.Implementation;
47
import net.bytebuddy.implementation.LoadedTypeInitializer;
48
import net.bytebuddy.implementation.attribute.AnnotationAppender;
49
import net.bytebuddy.implementation.attribute.AnnotationRetention;
50
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
51
import net.bytebuddy.implementation.attribute.FieldAttributeAppender;
52
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
53
import net.bytebuddy.implementation.attribute.RecordComponentAttributeAppender;
54
import net.bytebuddy.implementation.attribute.TypeAttributeAppender;
55
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
56
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
57
import net.bytebuddy.implementation.bytecode.StackManipulation;
58
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
59
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
60
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
61
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
62
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
63
import net.bytebuddy.pool.TypePool;
64
import net.bytebuddy.utility.AsmClassReader;
65
import net.bytebuddy.utility.AsmClassWriter;
66
import net.bytebuddy.utility.CompoundList;
67
import net.bytebuddy.utility.OpenedClassReader;
68
import net.bytebuddy.utility.nullability.AlwaysNull;
69
import net.bytebuddy.utility.nullability.MaybeNull;
70
import net.bytebuddy.utility.nullability.UnknownNull;
71
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
72
import net.bytebuddy.utility.visitor.ContextClassVisitor;
73
import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
74
import org.objectweb.asm.AnnotationVisitor;
75
import org.objectweb.asm.ClassReader;
76
import org.objectweb.asm.ClassVisitor;
77
import org.objectweb.asm.ClassWriter;
78
import org.objectweb.asm.ConstantDynamic;
79
import org.objectweb.asm.FieldVisitor;
80
import org.objectweb.asm.Handle;
81
import org.objectweb.asm.Label;
82
import org.objectweb.asm.MethodVisitor;
83
import org.objectweb.asm.ModuleVisitor;
84
import org.objectweb.asm.Opcodes;
85
import org.objectweb.asm.RecordComponentVisitor;
86
import org.objectweb.asm.Type;
87
import org.objectweb.asm.TypePath;
88
import org.objectweb.asm.commons.ClassRemapper;
89
import org.objectweb.asm.commons.Remapper;
90
import org.objectweb.asm.commons.SimpleRemapper;
91

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

108
import static net.bytebuddy.matcher.ElementMatchers.is;
109
import static net.bytebuddy.matcher.ElementMatchers.isSubTypeOf;
110
import static net.bytebuddy.matcher.ElementMatchers.not;
111

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

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

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

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

144
    /**
145
     * An field pool that allows a lookup for how to implement a field.
146
     */
147
    interface FieldPool {
148

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

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

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

171
            /**
172
             * Returns the field that this record represents.
173
             *
174
             * @return The field that this record represents.
175
             */
176
            FieldDescription getField();
177

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

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

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

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

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

216
                /**
217
                 * The implemented field.
218
                 */
219
                private final FieldDescription fieldDescription;
220

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

230
                /**
231
                 * {@inheritDoc}
232
                 */
233
                public boolean isImplicit() {
234
                    return true;
1✔
235
                }
236

237
                /**
238
                 * {@inheritDoc}
239
                 */
240
                public FieldDescription getField() {
241
                    return fieldDescription;
1✔
242
                }
243

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

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

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

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

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

289
                /**
290
                 * The attribute appender for the field.
291
                 */
292
                private final FieldAttributeAppender attributeAppender;
293

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

301
                /**
302
                 * The implemented field.
303
                 */
304
                private final FieldDescription fieldDescription;
305

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

321
                /**
322
                 * {@inheritDoc}
323
                 */
324
                public boolean isImplicit() {
325
                    return false;
1✔
326
                }
327

328
                /**
329
                 * {@inheritDoc}
330
                 */
331
                public FieldDescription getField() {
332
                    return fieldDescription;
1✔
333
                }
334

335
                /**
336
                 * {@inheritDoc}
337
                 */
338
                public FieldAttributeAppender getFieldAppender() {
339
                    return attributeAppender;
1✔
340
                }
341

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

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

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

376
        /**
377
         * A field pool that does not allow any look ups.
378
         */
379
        enum Disabled implements FieldPool {
1✔
380

381
            /**
382
             * The singleton instance.
383
             */
384
            INSTANCE;
1✔
385

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

395
    /**
396
     * An method pool that allows a lookup for how to implement a method.
397
     */
398
    interface MethodPool {
399

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

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

415
            /**
416
             * Returns the sort of this method instrumentation.
417
             *
418
             * @return The sort of this method instrumentation.
419
             */
420
            Sort getSort();
421

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

430
            /**
431
             * The visibility to enforce for this method.
432
             *
433
             * @return The visibility to enforce for this method.
434
             */
435
            Visibility getVisibility();
436

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

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

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

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

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

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

491
            /**
492
             * The sort of an entry.
493
             */
494
            enum Sort {
1✔
495

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

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

506
                /**
507
                 * Describes a method that is implemented in byte code.
508
                 */
509
                IMPLEMENTED(true, true);
1✔
510

511
                /**
512
                 * Indicates if this sort defines a method, with or without byte code.
513
                 */
514
                private final boolean define;
515

516
                /**
517
                 * Indicates if this sort defines byte code.
518
                 */
519
                private final boolean implement;
520

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

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

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

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

557
                /**
558
                 * The undefined method.
559
                 */
560
                private final MethodDescription methodDescription;
561

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

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

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

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

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

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

606
                /**
607
                 * {@inheritDoc}
608
                 */
609
                public MethodDescription getMethod() {
610
                    return methodDescription;
1✔
611
                }
612

613
                /**
614
                 * {@inheritDoc}
615
                 */
616
                public Visibility getVisibility() {
617
                    return methodDescription.getVisibility();
×
618
                }
619

620
                /**
621
                 * {@inheritDoc}
622
                 */
623
                public Sort getSort() {
624
                    return Sort.SKIPPED;
1✔
625
                }
626

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

636
            /**
637
             * A base implementation of an abstract entry that defines a method.
638
             */
639
            abstract class ForDefinedMethod implements Record {
1✔
640

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

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

669
                    /**
670
                     * The implemented method.
671
                     */
672
                    private final MethodDescription methodDescription;
673

674
                    /**
675
                     * The byte code appender to apply.
676
                     */
677
                    private final ByteCodeAppender byteCodeAppender;
678

679
                    /**
680
                     * The method attribute appender to apply.
681
                     */
682
                    private final MethodAttributeAppender methodAttributeAppender;
683

684
                    /**
685
                     * The represented method's minimum visibility.
686
                     */
687
                    private final Visibility visibility;
688

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

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

717
                    /**
718
                     * {@inheritDoc}
719
                     */
720
                    public MethodDescription getMethod() {
721
                        return methodDescription;
1✔
722
                    }
723

724
                    /**
725
                     * {@inheritDoc}
726
                     */
727
                    public Sort getSort() {
728
                        return Sort.IMPLEMENTED;
1✔
729
                    }
730

731
                    /**
732
                     * {@inheritDoc}
733
                     */
734
                    public Visibility getVisibility() {
735
                        return visibility;
1✔
736
                    }
737

738
                    /**
739
                     * {@inheritDoc}
740
                     */
741
                    public void applyHead(MethodVisitor methodVisitor) {
742
                        /* do nothing */
743
                    }
1✔
744

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

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

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

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

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

786
                    /**
787
                     * The implemented method.
788
                     */
789
                    private final MethodDescription methodDescription;
790

791
                    /**
792
                     * The method attribute appender to apply.
793
                     */
794
                    private final MethodAttributeAppender methodAttributeAppender;
795

796
                    /**
797
                     * The represented method's minimum visibility.
798
                     */
799
                    private final Visibility visibility;
800

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

814
                    /**
815
                     * {@inheritDoc}
816
                     */
817
                    public MethodDescription getMethod() {
818
                        return methodDescription;
1✔
819
                    }
820

821
                    /**
822
                     * {@inheritDoc}
823
                     */
824
                    public Sort getSort() {
825
                        return Sort.DEFINED;
1✔
826
                    }
827

828
                    /**
829
                     * {@inheritDoc}
830
                     */
831
                    public Visibility getVisibility() {
832
                        return visibility;
1✔
833
                    }
834

835
                    /**
836
                     * {@inheritDoc}
837
                     */
838
                    public void applyHead(MethodVisitor methodVisitor) {
839
                        /* do nothing */
840
                    }
1✔
841

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

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

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

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

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

877
                    /**
878
                     * The implemented method.
879
                     */
880
                    private final MethodDescription methodDescription;
881

882
                    /**
883
                     * The annotation value to define.
884
                     */
885
                    private final AnnotationValue<?, ?> annotationValue;
886

887
                    /**
888
                     * The method attribute appender to apply.
889
                     */
890
                    private final MethodAttributeAppender methodAttributeAppender;
891

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

907
                    /**
908
                     * {@inheritDoc}
909
                     */
910
                    public MethodDescription getMethod() {
911
                        return methodDescription;
1✔
912
                    }
913

914
                    /**
915
                     * {@inheritDoc}
916
                     */
917
                    public Sort getSort() {
918
                        return Sort.DEFINED;
1✔
919
                    }
920

921
                    /**
922
                     * {@inheritDoc}
923
                     */
924
                    public Visibility getVisibility() {
925
                        return methodDescription.getVisibility();
1✔
926
                    }
927

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

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

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

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

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

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

978
                    /**
979
                     * The visibility bridge.
980
                     */
981
                    private final MethodDescription visibilityBridge;
982

983
                    /**
984
                     * The method the visibility bridge invokes.
985
                     */
986
                    private final MethodDescription bridgeTarget;
987

988
                    /**
989
                     * The type on which the bridge method is invoked.
990
                     */
991
                    private final TypeDescription bridgeType;
992

993
                    /**
994
                     * The attribute appender to apply to the visibility bridge.
995
                     */
996
                    private final MethodAttributeAppender attributeAppender;
997

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

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

1048
                    /**
1049
                     * {@inheritDoc}
1050
                     */
1051
                    public MethodDescription getMethod() {
1052
                        return visibilityBridge;
1✔
1053
                    }
1054

1055
                    /**
1056
                     * {@inheritDoc}
1057
                     */
1058
                    public Sort getSort() {
1059
                        return Sort.IMPLEMENTED;
1✔
1060
                    }
1061

1062
                    /**
1063
                     * {@inheritDoc}
1064
                     */
1065
                    public Visibility getVisibility() {
1066
                        return bridgeTarget.getVisibility();
1✔
1067
                    }
1068

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

1079
                    /**
1080
                     * {@inheritDoc}
1081
                     */
1082
                    public void applyHead(MethodVisitor methodVisitor) {
1083
                        /* do nothing */
1084
                    }
1✔
1085

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

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

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

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

1121
                    /**
1122
                     * A method describing a visibility bridge.
1123
                     */
1124
                    protected static class VisibilityBridge extends MethodDescription.InDefinedShape.AbstractBase {
1125

1126
                        /**
1127
                         * The instrumented type.
1128
                         */
1129
                        private final TypeDescription instrumentedType;
1130

1131
                        /**
1132
                         * The method that is the target of the bridge.
1133
                         */
1134
                        private final MethodDescription bridgeTarget;
1135

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

1147
                        /**
1148
                         * {@inheritDoc}
1149
                         */
1150
                        @Nonnull
1151
                        public TypeDescription getDeclaringType() {
1152
                            return instrumentedType;
1✔
1153
                        }
1154

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

1162
                        /**
1163
                         * {@inheritDoc}
1164
                         */
1165
                        public TypeDescription.Generic getReturnType() {
1166
                            return bridgeTarget.getReturnType().asRawType();
1✔
1167
                        }
1168

1169
                        /**
1170
                         * {@inheritDoc}
1171
                         */
1172
                        public TypeList.Generic getExceptionTypes() {
1173
                            return bridgeTarget.getExceptionTypes().asRawTypes();
1✔
1174
                        }
1175

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

1184
                        /**
1185
                         * {@inheritDoc}
1186
                         */
1187
                        public TypeList.Generic getTypeVariables() {
1188
                            return new TypeList.Generic.Empty();
1✔
1189
                        }
1190

1191
                        /**
1192
                         * {@inheritDoc}
1193
                         */
1194
                        public AnnotationList getDeclaredAnnotations() {
1195
                            return bridgeTarget.getDeclaredAnnotations();
1✔
1196
                        }
1197

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

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

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

1223
                /**
1224
                 * The delegate for implementing the bridge's target.
1225
                 */
1226
                private final Record delegate;
1227

1228
                /**
1229
                 * The instrumented type that defines the bridge methods and the bridge target.
1230
                 */
1231
                private final TypeDescription instrumentedType;
1232

1233
                /**
1234
                 * The target of the bridge method.
1235
                 */
1236
                private final MethodDescription bridgeTarget;
1237

1238
                /**
1239
                 * A collection of all tokens representing all bridge methods.
1240
                 */
1241
                private final Set<MethodDescription.TypeToken> bridgeTypes;
1242

1243
                /**
1244
                 * The attribute appender being applied for the bridge target.
1245
                 */
1246
                private final MethodAttributeAppender attributeAppender;
1247

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

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

1295
                /**
1296
                 * {@inheritDoc}
1297
                 */
1298
                public Sort getSort() {
1299
                    return delegate.getSort();
1✔
1300
                }
1301

1302
                /**
1303
                 * {@inheritDoc}
1304
                 */
1305
                public MethodDescription getMethod() {
1306
                    return bridgeTarget;
×
1307
                }
1308

1309
                /**
1310
                 * {@inheritDoc}
1311
                 */
1312
                public Visibility getVisibility() {
1313
                    return delegate.getVisibility();
1✔
1314
                }
1315

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

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

1355
                /**
1356
                 * {@inheritDoc}
1357
                 */
1358
                public void applyHead(MethodVisitor methodVisitor) {
1359
                    delegate.applyHead(methodVisitor);
1✔
1360
                }
1✔
1361

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

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

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

1385
                /**
1386
                 * A method representing an accessor bridge method.
1387
                 */
1388
                protected static class AccessorBridge extends MethodDescription.InDefinedShape.AbstractBase {
1389

1390
                    /**
1391
                     * The target method of the bridge.
1392
                     */
1393
                    private final MethodDescription bridgeTarget;
1394

1395
                    /**
1396
                     * The bridge's type token.
1397
                     */
1398
                    private final MethodDescription.TypeToken bridgeType;
1399

1400
                    /**
1401
                     * The instrumented type defining the bridge target.
1402
                     */
1403
                    private final TypeDescription instrumentedType;
1404

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

1418
                    /**
1419
                     * {@inheritDoc}
1420
                     */
1421
                    @Nonnull
1422
                    public TypeDescription getDeclaringType() {
1423
                        return instrumentedType;
1✔
1424
                    }
1425

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

1433
                    /**
1434
                     * {@inheritDoc}
1435
                     */
1436
                    public TypeDescription.Generic getReturnType() {
1437
                        return bridgeType.getReturnType().asGenericType();
1✔
1438
                    }
1439

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

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

1455
                    /**
1456
                     * {@inheritDoc}
1457
                     */
1458
                    public TypeList.Generic getTypeVariables() {
1459
                        return new TypeList.Generic.Empty();
1✔
1460
                    }
1461

1462
                    /**
1463
                     * {@inheritDoc}
1464
                     */
1465
                    public AnnotationList getDeclaredAnnotations() {
1466
                        return new AnnotationList.Empty();
1✔
1467
                    }
1468

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

1476
                    /**
1477
                     * {@inheritDoc}
1478
                     */
1479
                    public String getInternalName() {
1480
                        return bridgeTarget.getInternalName();
1✔
1481
                    }
1482
                }
1483

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

1489
                    /**
1490
                     * The target method of the bridge.
1491
                     */
1492
                    private final MethodDescription bridgeTarget;
1493

1494
                    /**
1495
                     * The instrumented type defining the bridge target.
1496
                     */
1497
                    private final TypeDescription instrumentedType;
1498

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

1510
                    /**
1511
                     * {@inheritDoc}
1512
                     */
1513
                    @Nonnull
1514
                    public TypeDescription getDeclaringType() {
1515
                        return instrumentedType;
1✔
1516
                    }
1517

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

1525
                    /**
1526
                     * {@inheritDoc}
1527
                     */
1528
                    public TypeDescription.Generic getReturnType() {
1529
                        return bridgeTarget.getReturnType();
1✔
1530
                    }
1531

1532
                    /**
1533
                     * {@inheritDoc}
1534
                     */
1535
                    public TypeList.Generic getExceptionTypes() {
1536
                        return bridgeTarget.getExceptionTypes();
×
1537
                    }
1538

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

1547
                    /**
1548
                     * {@inheritDoc}
1549
                     */
1550
                    public TypeList.Generic getTypeVariables() {
1551
                        return bridgeTarget.getTypeVariables();
×
1552
                    }
1553

1554
                    /**
1555
                     * {@inheritDoc}
1556
                     */
1557
                    public AnnotationList getDeclaredAnnotations() {
1558
                        return bridgeTarget.getDeclaredAnnotations();
×
1559
                    }
1560

1561
                    /**
1562
                     * {@inheritDoc}
1563
                     */
1564
                    public int getModifiers() {
1565
                        return bridgeTarget.getModifiers();
1✔
1566
                    }
1567

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

1579
    /**
1580
     * An record component pool that allows a lookup for how to implement a record component.
1581
     */
1582
    interface RecordComponentPool {
1583

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

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

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

1606
            /**
1607
             * Returns the record component that this record represents.
1608
             *
1609
             * @return The record component that this record represents.
1610
             */
1611
            RecordComponentDescription getRecordComponent();
1612

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

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

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

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

1642
                /**
1643
                 * The implemented record component.
1644
                 */
1645
                private final RecordComponentDescription recordComponentDescription;
1646

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

1656
                /**
1657
                 * {@inheritDoc}
1658
                 */
1659
                public boolean isImplicit() {
1660
                    return true;
1✔
1661
                }
1662

1663
                /**
1664
                 * {@inheritDoc}
1665
                 */
1666
                public RecordComponentDescription getRecordComponent() {
1667
                    return recordComponentDescription;
×
1668
                }
1669

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

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

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

1700
            /**
1701
             * A record for a rich record component with attributes.
1702
             */
1703
            @HashCodeAndEqualsPlugin.Enhance
1704
            class ForExplicitRecordComponent implements Record {
1705

1706
                /**
1707
                 * The attribute appender for the record component.
1708
                 */
1709
                private final RecordComponentAttributeAppender attributeAppender;
1710

1711
                /**
1712
                 * The implemented record component.
1713
                 */
1714
                private final RecordComponentDescription recordComponentDescription;
1715

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

1727
                /**
1728
                 * {@inheritDoc}
1729
                 */
1730
                public boolean isImplicit() {
1731
                    return false;
1✔
1732
                }
1733

1734
                /**
1735
                 * {@inheritDoc}
1736
                 */
1737
                public RecordComponentDescription getRecordComponent() {
1738
                    return recordComponentDescription;
×
1739
                }
1740

1741
                /**
1742
                 * {@inheritDoc}
1743
                 */
1744
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1745
                    return attributeAppender;
1✔
1746
                }
1747

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

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

1770
        /**
1771
         * A record component pool that does not allow any look ups.
1772
         */
1773
        enum Disabled implements RecordComponentPool {
1✔
1774

1775
            /**
1776
             * The singleton instance.
1777
             */
1778
            INSTANCE;
1✔
1779

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

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

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

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

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

1822
        /**
1823
         * The instrumented type to be created.
1824
         */
1825
        protected final TypeDescription instrumentedType;
1826

1827
        /**
1828
         * The class file specified by the user.
1829
         */
1830
        protected final ClassFileVersion classFileVersion;
1831

1832
        /**
1833
         * The field pool to use.
1834
         */
1835
        protected final FieldPool fieldPool;
1836

1837
        /**
1838
         * The record component pool to use.
1839
         */
1840
        protected final RecordComponentPool recordComponentPool;
1841

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

1847
        /**
1848
         * The instrumented type's declared fields.
1849
         */
1850
        protected final FieldList<FieldDescription.InDefinedShape> fields;
1851

1852
        /**
1853
         * The instrumented type's methods that are declared or inherited.
1854
         */
1855
        protected final MethodList<?> methods;
1856

1857
        /**
1858
         * The instrumented methods relevant to this type creation.
1859
         */
1860
        protected final MethodList<?> instrumentedMethods;
1861

1862
        /**
1863
         * The instrumented type's record components.
1864
         */
1865
        protected final RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents;
1866

1867
        /**
1868
         * The loaded type initializer to apply onto the created type after loading.
1869
         */
1870
        protected final LoadedTypeInitializer loadedTypeInitializer;
1871

1872
        /**
1873
         * The type initializer to include in the created type's type initializer.
1874
         */
1875
        protected final TypeInitializer typeInitializer;
1876

1877
        /**
1878
         * The type attribute appender to apply onto the instrumented type.
1879
         */
1880
        protected final TypeAttributeAppender typeAttributeAppender;
1881

1882
        /**
1883
         * The ASM visitor wrapper to apply onto the class writer.
1884
         */
1885
        protected final AsmVisitorWrapper asmVisitorWrapper;
1886

1887
        /**
1888
         * The annotation value filter factory to apply.
1889
         */
1890
        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
1891

1892
        /**
1893
         * The annotation retention to apply.
1894
         */
1895
        protected final AnnotationRetention annotationRetention;
1896

1897
        /**
1898
         * The naming strategy for auxiliary types to apply.
1899
         */
1900
        protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1901

1902
        /**
1903
         * The implementation context factory to apply.
1904
         */
1905
        protected final Implementation.Context.Factory implementationContextFactory;
1906

1907
        /**
1908
         * Determines if a type should be explicitly validated.
1909
         */
1910
        protected final TypeValidation typeValidation;
1911

1912
        /**
1913
         * The class reader factory to use.
1914
         */
1915
        protected final AsmClassReader.Factory classReaderFactory;
1916

1917
        /**
1918
         * The class writer factory to use.
1919
         */
1920
        protected final AsmClassWriter.Factory classWriterFactory;
1921

1922
        /**
1923
         * The type pool to use for computing stack map frames, if required.
1924
         */
1925
        protected final TypePool typePool;
1926

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

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

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

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

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

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

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

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

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

2294
        /**
2295
         * An unresolved type.
2296
         */
2297
        @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2298
        protected class UnresolvedType {
2299

2300
            /**
2301
             * The type's binary representation.
2302
             */
2303
            private final byte[] binaryRepresentation;
2304

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

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

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

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

2345
        /**
2346
         * A key to represent a unique signature.
2347
         */
2348
        protected static class SignatureKey {
2349

2350
            /**
2351
             * The represented internal name.
2352
             */
2353
            private final String internalName;
2354

2355
            /**
2356
             * The represented descriptor.
2357
             */
2358
            private final String descriptor;
2359

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

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

2379
            @Override
2380
            public int hashCode() {
2381
                return 17 + internalName.hashCode() + 31 * descriptor.hashCode();
1✔
2382
            }
2383
        }
2384

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

2390
            /**
2391
             * Indicates that a method has no method parameters.
2392
             */
2393
            private static final String NO_PARAMETERS = "()";
2394

2395
            /**
2396
             * Indicates that a method returns void.
2397
             */
2398
            private static final String RETURNS_VOID = "V";
2399

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

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

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

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

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

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

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

2483
            @Override
2484
            public void visitPermittedSubclass(String permittedSubclass) {
2485
                constraint.assertPermittedSubclass();
×
2486
                super.visitPermittedSubclass(permittedSubclass);
×
2487
            }
×
2488

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

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

2503
            @Override
2504
            public void visitNestHost(String nestHost) {
2505
                constraint.assertNestMate();
×
2506
                super.visitNestHost(nestHost);
×
2507
            }
×
2508

2509
            @Override
2510
            public void visitNestMember(String nestMember) {
2511
                constraint.assertNestMate();
×
2512
                super.visitNestMember(nestMember);
×
2513
            }
×
2514

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

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

2599
            /**
2600
             * A constraint for members that are legal for a given type.
2601
             */
2602
            protected interface Constraint {
2603

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

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

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

2647
                /**
2648
                 * Asserts the legitimacy of an annotation for the instrumented type.
2649
                 */
2650
                void assertAnnotation();
2651

2652
                /**
2653
                 * Asserts the legitimacy of a type annotation for the instrumented type.
2654
                 */
2655
                void assertTypeAnnotation();
2656

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

2664
                /**
2665
                 * Asserts if it is legal to invoke a default method from a type.
2666
                 */
2667
                void assertDefaultMethodCall();
2668

2669
                /**
2670
                 * Asserts the capability to store a type constant in the class's constant pool.
2671
                 */
2672
                void assertTypeInConstantPool();
2673

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

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

2684
                /**
2685
                 * Asserts the capability to invoke a method dynamically.
2686
                 */
2687
                void assertInvokeDynamic();
2688

2689
                /**
2690
                 * Asserts the capability of executing a subroutine.
2691
                 */
2692
                void assertSubRoutine();
2693

2694
                /**
2695
                 * Asserts the capability of storing a dynamic value in the constant pool.
2696
                 */
2697
                void assertDynamicValueInConstantPool();
2698

2699
                /**
2700
                 * Asserts the capability of storing nest mate information.
2701
                 */
2702
                void assertNestMate();
2703

2704
                /**
2705
                 * Asserts the presence of a record component.
2706
                 */
2707
                void assertRecord();
2708

2709
                /**
2710
                 * Asserts the presence of a permitted subclass.
2711
                 */
2712
                void assertPermittedSubclass();
2713

2714
                /**
2715
                 * Represents the constraint of a class type.
2716
                 */
2717
                enum ForClass implements Constraint {
1✔
2718

2719
                    /**
2720
                     * Represents the constraints of a non-abstract class.
2721
                     */
2722
                    MANIFEST(true),
1✔
2723

2724
                    /**
2725
                     * Represents the constraints of an abstract class.
2726
                     */
2727
                    ABSTRACT(false);
1✔
2728

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

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

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

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

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

2774
                    /**
2775
                     * {@inheritDoc}
2776
                     */
2777
                    public void assertAnnotation() {
2778
                        /* do nothing */
2779
                    }
1✔
2780

2781
                    /**
2782
                     * {@inheritDoc}
2783
                     */
2784
                    public void assertTypeAnnotation() {
2785
                        /* do nothing */
2786
                    }
1✔
2787

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

2795
                    /**
2796
                     * {@inheritDoc}
2797
                     */
2798
                    public void assertDefaultMethodCall() {
2799
                        /* do nothing */
2800
                    }
1✔
2801

2802
                    /**
2803
                     * {@inheritDoc}
2804
                     */
2805
                    public void assertTypeInConstantPool() {
2806
                        /* do nothing */
2807
                    }
1✔
2808

2809
                    /**
2810
                     * {@inheritDoc}
2811
                     */
2812
                    public void assertMethodTypeInConstantPool() {
2813
                        /* do nothing */
2814
                    }
1✔
2815

2816
                    /**
2817
                     * {@inheritDoc}
2818
                     */
2819
                    public void assertHandleInConstantPool() {
2820
                        /* do nothing */
2821
                    }
1✔
2822

2823
                    /**
2824
                     * {@inheritDoc}
2825
                     */
2826
                    public void assertInvokeDynamic() {
2827
                        /* do nothing */
2828
                    }
1✔
2829

2830
                    /**
2831
                     * {@inheritDoc}
2832
                     */
2833
                    public void assertSubRoutine() {
2834
                        /* do nothing */
2835
                    }
1✔
2836

2837
                    /**
2838
                     * {@inheritDoc}
2839
                     */
2840
                    public void assertDynamicValueInConstantPool() {
2841
                        /* do nothing */
2842
                    }
×
2843

2844
                    /**
2845
                     * {@inheritDoc}
2846
                     */
2847
                    public void assertNestMate() {
2848
                        /* do nothing */
2849
                    }
×
2850

2851
                    /**
2852
                     * {@inheritDoc}
2853
                     */
2854
                    public void assertRecord() {
2855
                        /* do nothing */
2856
                    }
×
2857

2858
                    /**
2859
                     * {@inheritDoc}
2860
                     */
2861
                    public void assertPermittedSubclass() {
2862
                        /* do nothing */
2863
                    }
×
2864
                }
2865

2866
                /**
2867
                 * Represents the constraint of a package type.
2868
                 */
2869
                enum ForPackageType implements Constraint {
1✔
2870

2871
                    /**
2872
                     * The singleton instance.
2873
                     */
2874
                    INSTANCE;
1✔
2875

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

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

2898
                    /**
2899
                     * {@inheritDoc}
2900
                     */
2901
                    public void assertAnnotation() {
2902
                        /* do nothing */
2903
                    }
1✔
2904

2905
                    /**
2906
                     * {@inheritDoc}
2907
                     */
2908
                    public void assertTypeAnnotation() {
2909
                        /* do nothing */
2910
                    }
×
2911

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

2919
                    /**
2920
                     * {@inheritDoc}
2921
                     */
2922
                    public void assertDefaultMethodCall() {
2923
                        /* do nothing */
2924
                    }
×
2925

2926
                    /**
2927
                     * {@inheritDoc}
2928
                     */
2929
                    public void assertTypeInConstantPool() {
2930
                        /* do nothing */
2931
                    }
×
2932

2933
                    /**
2934
                     * {@inheritDoc}
2935
                     */
2936
                    public void assertMethodTypeInConstantPool() {
2937
                        /* do nothing */
2938
                    }
×
2939

2940
                    /**
2941
                     * {@inheritDoc}
2942
                     */
2943
                    public void assertHandleInConstantPool() {
2944
                        /* do nothing */
2945
                    }
×
2946

2947
                    /**
2948
                     * {@inheritDoc}
2949
                     */
2950
                    public void assertInvokeDynamic() {
2951
                        /* do nothing */
2952
                    }
×
2953

2954
                    /**
2955
                     * {@inheritDoc}
2956
                     */
2957
                    public void assertSubRoutine() {
2958
                        /* do nothing */
2959
                    }
×
2960

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

2972
                    /**
2973
                     * {@inheritDoc}
2974
                     */
2975
                    public void assertDynamicValueInConstantPool() {
2976
                        /* do nothing */
2977
                    }
×
2978

2979
                    /**
2980
                     * {@inheritDoc}
2981
                     */
2982
                    public void assertNestMate() {
2983
                        /* do nothing */
2984
                    }
×
2985

2986
                    /**
2987
                     * {@inheritDoc}
2988
                     */
2989
                    public void assertRecord() {
2990
                        /* do nothing */
2991
                    }
×
2992

2993
                    /**
2994
                     * {@inheritDoc}
2995
                     */
2996
                    public void assertPermittedSubclass() {
2997
                        /* do nothing */
2998
                    }
×
2999
                }
3000

3001
                /**
3002
                 * Represents the constraint of an interface type.
3003
                 */
3004
                enum ForInterface implements Constraint {
1✔
3005

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

3011
                    /**
3012
                     * An interface type with the constraints for the Java versions 8+.
3013
                     */
3014
                    JAVA_8(false);
1✔
3015

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

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

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

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

3064
                    /**
3065
                     * {@inheritDoc}
3066
                     */
3067
                    public void assertAnnotation() {
3068
                        /* do nothing */
3069
                    }
1✔
3070

3071
                    /**
3072
                     * {@inheritDoc}
3073
                     */
3074
                    public void assertTypeAnnotation() {
3075
                        /* do nothing */
3076
                    }
×
3077

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

3085
                    /**
3086
                     * {@inheritDoc}
3087
                     */
3088
                    public void assertDefaultMethodCall() {
3089
                        /* do nothing */
3090
                    }
1✔
3091

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

3099
                    /**
3100
                     * {@inheritDoc}
3101
                     */
3102
                    public void assertTypeInConstantPool() {
3103
                        /* do nothing */
3104
                    }
×
3105

3106
                    /**
3107
                     * {@inheritDoc}
3108
                     */
3109
                    public void assertMethodTypeInConstantPool() {
3110
                        /* do nothing */
3111
                    }
×
3112

3113
                    /**
3114
                     * {@inheritDoc}
3115
                     */
3116
                    public void assertHandleInConstantPool() {
3117
                        /* do nothing */
3118
                    }
×
3119

3120
                    /**
3121
                     * {@inheritDoc}
3122
                     */
3123
                    public void assertInvokeDynamic() {
3124
                        /* do nothing */
3125
                    }
×
3126

3127
                    /**
3128
                     * {@inheritDoc}
3129
                     */
3130
                    public void assertSubRoutine() {
3131
                        /* do nothing */
3132
                    }
×
3133

3134
                    /**
3135
                     * {@inheritDoc}
3136
                     */
3137
                    public void assertDynamicValueInConstantPool() {
3138
                        /* do nothing */
3139
                    }
×
3140

3141
                    /**
3142
                     * {@inheritDoc}
3143
                     */
3144
                    public void assertNestMate() {
3145
                        /* do nothing */
3146
                    }
×
3147

3148
                    /**
3149
                     * {@inheritDoc}
3150
                     */
3151
                    public void assertRecord() {
3152
                        /* do nothing */
3153
                    }
×
3154

3155
                    /**
3156
                     * {@inheritDoc}
3157
                     */
3158
                    public void assertPermittedSubclass() {
3159
                        /* do nothing */
3160
                    }
×
3161
                }
3162

3163
                /**
3164
                 * Represents the constraint of a record type.
3165
                 */
3166
                enum ForRecord implements Constraint {
1✔
3167

3168
                    /**
3169
                     * The singleton instance.
3170
                     */
3171
                    INSTANCE;
1✔
3172

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

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

3195
                    /**
3196
                     * {@inheritDoc}
3197
                     */
3198
                    public void assertAnnotation() {
3199
                        /* do nothing */
3200
                    }
×
3201

3202
                    /**
3203
                     * {@inheritDoc}
3204
                     */
3205
                    public void assertTypeAnnotation() {
3206
                        /* do nothing */
3207
                    }
×
3208

3209
                    /**
3210
                     * {@inheritDoc}
3211
                     */
3212
                    public void assertDefaultValue(String name) {
3213
                        /* do nothing */
3214
                    }
×
3215

3216
                    /**
3217
                     * {@inheritDoc}
3218
                     */
3219
                    public void assertDefaultMethodCall() {
3220
                        /* do nothing */
3221
                    }
×
3222

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

3232
                    /**
3233
                     * {@inheritDoc}
3234
                     */
3235
                    public void assertTypeInConstantPool() {
3236
                        /* do nothing */
3237
                    }
×
3238

3239
                    /**
3240
                     * {@inheritDoc}
3241
                     */
3242
                    public void assertMethodTypeInConstantPool() {
3243
                        /* do nothing */
3244
                    }
×
3245

3246
                    /**
3247
                     * {@inheritDoc}
3248
                     */
3249
                    public void assertHandleInConstantPool() {
3250
                        /* do nothing */
3251
                    }
×
3252

3253
                    /**
3254
                     * {@inheritDoc}
3255
                     */
3256
                    public void assertInvokeDynamic() {
3257
                        /* do nothing */
3258
                    }
×
3259

3260
                    /**
3261
                     * {@inheritDoc}
3262
                     */
3263
                    public void assertSubRoutine() {
3264
                        /* do nothing */
3265
                    }
×
3266

3267
                    /**
3268
                     * {@inheritDoc}
3269
                     */
3270
                    public void assertDynamicValueInConstantPool() {
3271
                        /* do nothing */
3272
                    }
×
3273

3274
                    /**
3275
                     * {@inheritDoc}
3276
                     */
3277
                    public void assertNestMate() {
3278
                        /* do nothing */
3279
                    }
×
3280

3281
                    /**
3282
                     * {@inheritDoc}
3283
                     */
3284
                    public void assertRecord() {
3285
                        /* do nothing */
3286
                    }
×
3287

3288
                    /**
3289
                     * {@inheritDoc}
3290
                     */
3291
                    public void assertPermittedSubclass() {
3292
                        /* do nothing */
3293
                    }
×
3294
                }
3295

3296
                /**
3297
                 * Represents the constraint of an annotation type.
3298
                 */
3299
                enum ForAnnotation implements Constraint {
1✔
3300

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

3306
                    /**
3307
                     * An annotation type with the constraints for the Java versions 8+.
3308
                     */
3309
                    JAVA_8(false);
1✔
3310

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

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

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

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

3357
                    /**
3358
                     * {@inheritDoc}
3359
                     */
3360
                    public void assertAnnotation() {
3361
                        /* do nothing */
3362
                    }
1✔
3363

3364
                    /**
3365
                     * {@inheritDoc}
3366
                     */
3367
                    public void assertTypeAnnotation() {
3368
                        /* do nothing */
3369
                    }
×
3370

3371
                    /**
3372
                     * {@inheritDoc}
3373
                     */
3374
                    public void assertDefaultValue(String name) {
3375
                        /* do nothing */
3376
                    }
1✔
3377

3378
                    /**
3379
                     * {@inheritDoc}
3380
                     */
3381
                    public void assertDefaultMethodCall() {
3382
                        /* do nothing */
3383
                    }
×
3384

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

3394
                    /**
3395
                     * {@inheritDoc}
3396
                     */
3397
                    public void assertTypeInConstantPool() {
3398
                        /* do nothing */
3399
                    }
×
3400

3401
                    /**
3402
                     * {@inheritDoc}
3403
                     */
3404
                    public void assertMethodTypeInConstantPool() {
3405
                        /* do nothing */
3406
                    }
×
3407

3408
                    /**
3409
                     * {@inheritDoc}
3410
                     */
3411
                    public void assertHandleInConstantPool() {
3412
                        /* do nothing */
3413
                    }
×
3414

3415
                    /**
3416
                     * {@inheritDoc}
3417
                     */
3418
                    public void assertInvokeDynamic() {
3419
                        /* do nothing */
3420
                    }
×
3421

3422
                    /**
3423
                     * {@inheritDoc}
3424
                     */
3425
                    public void assertSubRoutine() {
3426
                        /* do nothing */
3427
                    }
×
3428

3429
                    /**
3430
                     * {@inheritDoc}
3431
                     */
3432
                    public void assertDynamicValueInConstantPool() {
3433
                        /* do nothing */
3434
                    }
×
3435

3436
                    /**
3437
                     * {@inheritDoc}
3438
                     */
3439
                    public void assertNestMate() {
3440
                        /* do nothing */
3441
                    }
×
3442

3443
                    /**
3444
                     * {@inheritDoc}
3445
                     */
3446
                    public void assertRecord() {
3447
                        /* do nothing */
3448
                    }
×
3449

3450
                    /**
3451
                     * {@inheritDoc}
3452
                     */
3453
                    public void assertPermittedSubclass() {
3454
                        /* do nothing */
3455
                    }
×
3456
                }
3457

3458
                /**
3459
                 * Represents the constraint implied by a class file version.
3460
                 */
3461
                @HashCodeAndEqualsPlugin.Enhance
3462
                class ForClassFileVersion implements Constraint {
3463

3464
                    /**
3465
                     * The enforced class file version.
3466
                     */
3467
                    private final ClassFileVersion classFileVersion;
3468

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3633
                /**
3634
                 * A constraint implementation that summarizes several constraints.
3635
                 */
3636
                @HashCodeAndEqualsPlugin.Enhance
3637
                class Compound implements Constraint {
3638

3639
                    /**
3640
                     * A list of constraints that is enforced in the given order.
3641
                     */
3642
                    private final List<Constraint> constraints;
3643

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3822
            /**
3823
             * A field validator for checking default values.
3824
             */
3825
            protected class ValidatingFieldVisitor extends FieldVisitor {
3826

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

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

3843
            /**
3844
             * A method validator for checking default values.
3845
             */
3846
            protected class ValidatingMethodVisitor extends MethodVisitor {
3847

3848
                /**
3849
                 * The name of the method being visited.
3850
                 */
3851
                private final String name;
3852

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

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

3871
                @Override
3872
                @MaybeNull
3873
                public AnnotationVisitor visitAnnotationDefault() {
3874
                    constraint.assertDefaultValue(name);
1✔
3875
                    return super.visitAnnotationDefault();
1✔
3876
                }
3877

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

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

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

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

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

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

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

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

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

3961
            /**
3962
             * The original type's description.
3963
             */
3964
            protected final TypeDescription originalType;
3965

3966
            /**
3967
             * The class file locator for locating the original type's class file.
3968
             */
3969
            protected final ClassFileLocator classFileLocator;
3970

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

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

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

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

4095
            /**
4096
             * A context class visitor based on a {@link ContextRegistry}.
4097
             */
4098
            protected class RegistryContextClassVisitor extends ContextClassVisitor {
4099

4100
                /**
4101
                 * The context registry to use.
4102
                 */
4103
                private final ContextRegistry contextRegistry;
4104

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

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

4121
                @Override
4122
                public LoadedTypeInitializer getLoadedTypeInitializer() {
4123
                    return loadedTypeInitializer;
1✔
4124
                }
4125
            }
4126

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

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

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

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

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

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

4172
                /**
4173
                 * The method registry to use.
4174
                 */
4175
                private final MethodRegistry.Prepared methodRegistry;
4176

4177
                /**
4178
                 * The implementation target factory to use.
4179
                 */
4180
                private final Implementation.Target.Factory implementationTargetFactory;
4181

4182
                /**
4183
                 * The method rebase resolver to use for rebasing methods.
4184
                 */
4185
                private final MethodRebaseResolver methodRebaseResolver;
4186

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

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

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

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

4296
                /**
4297
                 * An initialization handler is responsible for handling the creation of the type initializer.
4298
                 */
4299
                protected interface InitializationHandler {
4300

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

4309
                    /**
4310
                     * An initialization handler that creates a new type initializer.
4311
                     */
4312
                    class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4313

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

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

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

4340
                        /**
4341
                         * The instrumented type.
4342
                         */
4343
                        protected final TypeDescription instrumentedType;
4344

4345
                        /**
4346
                         * The method pool record for the type initializer.
4347
                         */
4348
                        protected final MethodPool.Record record;
4349

4350
                        /**
4351
                         * The used annotation value filter factory.
4352
                         */
4353
                        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4354

4355
                        /**
4356
                         * The frame writer to use.
4357
                         */
4358
                        protected final FrameWriter frameWriter;
4359

4360
                        /**
4361
                         * The currently recorded stack size.
4362
                         */
4363
                        protected int stackSize;
4364

4365
                        /**
4366
                         * The currently recorded local variable length.
4367
                         */
4368
                        protected int localVariableLength;
4369

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

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

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

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

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

4476
                        /**
4477
                         * Invoked after the user code was visited.
4478
                         */
4479
                        protected abstract void onStart();
4480

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

4487
                        @Override
4488
                        public void visitMaxs(int stackSize, int localVariableLength) {
4489
                            this.stackSize = stackSize;
1✔
4490
                            this.localVariableLength = localVariableLength;
1✔
4491
                        }
1✔
4492

4493
                        @Override
4494
                        public abstract void visitEnd();
4495

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

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

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

4522
                        /**
4523
                         * A frame writer is responsible for adding empty frames on jump instructions.
4524
                         */
4525
                        protected interface FrameWriter {
4526

4527
                            /**
4528
                             * An empty array.
4529
                             */
4530
                            Object[] EMPTY = new Object[0];
1✔
4531

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

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

4547
                            /**
4548
                             * A non-operational frame writer.
4549
                             */
4550
                            enum NoOp implements FrameWriter {
1✔
4551

4552
                                /**
4553
                                 * The singleton instance.
4554
                                 */
4555
                                INSTANCE;
1✔
4556

4557
                                /**
4558
                                 * {@inheritDoc}
4559
                                 */
4560
                                public void onFrame(int type, int localVariableLength) {
4561
                                    /* do nothing */
4562
                                }
1✔
4563

4564
                                /**
4565
                                 * {@inheritDoc}
4566
                                 */
4567
                                public void emitFrame(MethodVisitor methodVisitor) {
4568
                                    /* do nothing */
4569
                                }
1✔
4570
                            }
4571

4572
                            /**
4573
                             * A frame writer that creates an expanded frame.
4574
                             */
4575
                            enum Expanding implements FrameWriter {
1✔
4576

4577
                                /**
4578
                                 * The singleton instance.
4579
                                 */
4580
                                INSTANCE;
1✔
4581

4582
                                /**
4583
                                 * {@inheritDoc}
4584
                                 */
4585
                                public void onFrame(int type, int localVariableLength) {
4586
                                    /* do nothing */
4587
                                }
1✔
4588

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

4598
                            /**
4599
                             * An active frame writer that creates the most efficient frame.
4600
                             */
4601
                            class Active implements FrameWriter {
1✔
4602

4603
                                /**
4604
                                 * The current length of the current local variable array.
4605
                                 */
4606
                                private int currentLocalVariableLength;
4607

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

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

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

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

4673
                            @Override
4674
                            protected void onStart() {
4675
                                /* do nothing */
4676
                            }
1✔
4677

4678
                            @Override
4679
                            public void visitEnd() {
4680
                                /* do nothing */
4681
                            }
1✔
4682

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

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

4704
                                @Override
4705
                                protected void onComplete(Implementation.Context implementationContext) {
4706
                                    /* do nothing */
4707
                                }
1✔
4708
                            }
4709

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

4716
                                /**
4717
                                 * The label that indicates the beginning of the active record.
4718
                                 */
4719
                                private final Label label;
4720

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

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

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

4759
                            }
4760
                        }
4761

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

4768
                            /**
4769
                             * A label marking the beginning of the appended code.
4770
                             */
4771
                            protected final Label appended;
4772

4773
                            /**
4774
                             * A label marking the beginning og the original type initializer's code.
4775
                             */
4776
                            protected final Label original;
4777

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

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

4806
                            @Override
4807
                            public void visitEnd() {
4808
                                mv.visitLabel(appended);
1✔
4809
                                frameWriter.emitFrame(mv);
1✔
4810
                            }
1✔
4811

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

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

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

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

4849
                                @Override
4850
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4851
                                    /* do nothing */
4852
                                }
1✔
4853
                            }
4854

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

4860
                                /**
4861
                                 * A label indicating the beginning of the record's code.
4862
                                 */
4863
                                private final Label label;
4864

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

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

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

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

4913
                    /**
4914
                     * The type initializer to apply.
4915
                     */
4916
                    private final TypeInitializer typeInitializer;
4917

4918
                    /**
4919
                     * A context registry to register the lazily created implementation context to.
4920
                     */
4921
                    private final ContextRegistry contextRegistry;
4922

4923
                    /**
4924
                     * The writer flags being used.
4925
                     */
4926
                    private final int writerFlags;
4927

4928
                    /**
4929
                     * The reader flags being used.
4930
                     */
4931
                    private final int readerFlags;
4932

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

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

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

4948
                    /**
4949
                     * 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.
4950
                     */
4951
                    private final Set<String> nestMembers;
4952

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

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

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

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

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

4982
                    /**
4983
                     * {@code true} if the modifiers for deprecation should be retained.
4984
                     */
4985
                    private boolean retainDeprecationModifiers;
4986

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

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

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

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

5095
                    @Override
5096
                    protected void onVisitNestHost(String nestHost) {
5097
                        onNestHost();
×
UNCOV
5098
                    }
×
5099

5100
                    @Override
5101
                    protected void onNestHost() {
5102
                        if (!instrumentedType.isNestHost()) {
1✔
UNCOV
5103
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5104
                        }
5105
                    }
1✔
5106

5107
                    @Override
5108
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5109
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
UNCOV
5110
                            cv.visitPermittedSubclass(permittedSubclass);
×
5111
                        }
UNCOV
5112
                    }
×
5113

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

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

5136
                    @Override
5137
                    protected void onAfterAttributes() {
5138
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5139
                    }
1✔
5140

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

5149
                    @Override
5150
                    @MaybeNull
5151
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5152
                        return annotationRetention.isEnabled()
1✔
5153
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5154
                                : IGNORE_ANNOTATION;
1✔
5155
                    }
5156

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

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

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

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

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

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

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

5338
                    @Override
5339
                    protected void onVisitNestMember(String nestMember) {
5340
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
UNCOV
5341
                            cv.visitNestMember(nestMember);
×
5342
                        }
UNCOV
5343
                    }
×
5344

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

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

5411
                    /**
5412
                     * A class visitor that deduplicates fields and methods, mostly when access bridge methods are
5413
                     * previously declared, but incomplete.
5414
                     */
5415
                    protected class DeduplicatingClassVisitor extends ClassVisitor {
5416

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

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

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

5457
                    /**
5458
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5459
                     * class file but that discards all code.
5460
                     */
5461
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5462

5463
                        /**
5464
                         * The field pool record to apply onto the field visitor.
5465
                         */
5466
                        private final FieldPool.Record record;
5467

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

5479
                        @Override
5480
                        @MaybeNull
5481
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5482
                            return annotationRetention.isEnabled()
×
5483
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
UNCOV
5484
                                    : IGNORE_ANNOTATION;
×
5485
                        }
5486

5487
                        @Override
5488
                        @MaybeNull
5489
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5490
                            return annotationRetention.isEnabled()
1✔
5491
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5492
                                    : IGNORE_ANNOTATION;
1✔
5493
                        }
5494

5495
                        @Override
5496
                        public void visitEnd() {
5497
                            record.apply(fv, annotationValueFilterFactory);
1✔
5498
                            super.visitEnd();
1✔
5499
                        }
1✔
5500
                    }
5501

5502
                    /**
5503
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5504
                     * in the class file but discards all code.
5505
                     */
5506
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5507

5508
                        /**
5509
                         * The record component pool record to apply onto the record component visitor.
5510
                         */
5511
                        private final RecordComponentPool.Record record;
5512

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

5524
                        @Override
5525
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5526
                            return annotationRetention.isEnabled()
×
5527
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
UNCOV
5528
                                    : IGNORE_ANNOTATION;
×
5529
                        }
5530

5531
                        @Override
5532
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5533
                            return annotationRetention.isEnabled()
×
5534
                                    ? super.visitAnnotation(descriptor, visible)
×
UNCOV
5535
                                    : IGNORE_ANNOTATION;
×
5536
                        }
5537

5538
                        @Override
5539
                        public void visitEnd() {
5540
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5541
                            super.visitEnd();
×
UNCOV
5542
                        }
×
5543
                    }
5544

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

5551
                        /**
5552
                         * The method visitor of the actual method.
5553
                         */
5554
                        private final MethodVisitor actualMethodVisitor;
5555

5556
                        /**
5557
                         * The method pool entry to apply.
5558
                         */
5559
                        private final MethodPool.Record record;
5560

5561
                        /**
5562
                         * The resolution of a potential rebased method.
5563
                         */
5564
                        private final MethodRebaseResolver.Resolution resolution;
5565

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

5583
                        @Override
5584
                        @MaybeNull
5585
                        public AnnotationVisitor visitAnnotationDefault() {
UNCOV
5586
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5587
                        }
5588

5589
                        @Override
5590
                        @MaybeNull
5591
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5592
                            return annotationRetention.isEnabled()
×
5593
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
UNCOV
5594
                                    : IGNORE_ANNOTATION;
×
5595
                        }
5596

5597
                        @Override
5598
                        @MaybeNull
5599
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5600
                            return annotationRetention.isEnabled()
1✔
5601
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5602
                                    : IGNORE_ANNOTATION;
1✔
5603
                        }
5604

5605
                        @Override
5606
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5607
                            if (annotationRetention.isEnabled()) {
1✔
5608
                                super.visitAnnotableParameterCount(count, visible);
1✔
5609
                            }
5610
                        }
1✔
5611

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

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

5672
                        @Override
5673
                        public void visitMaxs(int stackSize, int localVariableLength) {
5674
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5675
                        }
1✔
5676
                    }
5677

5678
                    /**
5679
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5680
                     * class file but that discards all code.
5681
                     */
5682
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5683

5684
                        /**
5685
                         * The method visitor to which the actual method is to be written to.
5686
                         */
5687
                        private final MethodVisitor actualMethodVisitor;
5688

5689
                        /**
5690
                         * The method pool entry to apply.
5691
                         */
5692
                        private final MethodPool.Record record;
5693

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

5707
                        @Override
5708
                        @MaybeNull
5709
                        public AnnotationVisitor visitAnnotationDefault() {
UNCOV
5710
                            return IGNORE_ANNOTATION;
×
5711
                        }
5712

5713
                        @Override
5714
                        @MaybeNull
5715
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5716
                            return annotationRetention.isEnabled()
×
5717
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
UNCOV
5718
                                    : IGNORE_ANNOTATION;
×
5719
                        }
5720

5721
                        @Override
5722
                        @MaybeNull
5723
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5724
                            return annotationRetention.isEnabled()
×
5725
                                    ? super.visitAnnotation(descriptor, visible)
×
UNCOV
5726
                                    : IGNORE_ANNOTATION;
×
5727
                        }
5728

5729
                        @Override
5730
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5731
                            if (annotationRetention.isEnabled()) {
×
UNCOV
5732
                                super.visitAnnotableParameterCount(count, visible);
×
5733
                            }
UNCOV
5734
                        }
×
5735

5736
                        @Override
5737
                        @MaybeNull
5738
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5739
                            return annotationRetention.isEnabled()
×
5740
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
UNCOV
5741
                                    : IGNORE_ANNOTATION;
×
5742
                        }
5743

5744
                        @Override
5745
                        public void visitCode() {
5746
                            mv = IGNORE_METHOD;
×
UNCOV
5747
                        }
×
5748

5749
                        @Override
5750
                        public void visitEnd() {
5751
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5752
                            actualMethodVisitor.visitEnd();
1✔
5753
                        }
1✔
5754
                    }
5755
                }
5756
            }
5757

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

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

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

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

5843
                    /**
5844
                     * The instrumented type.
5845
                     */
5846
                    private final TypeDescription instrumentedType;
5847

5848
                    /**
5849
                     * Creates a lazy field list.
5850
                     *
5851
                     * @param instrumentedType The instrumented type.
5852
                     */
5853
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
5854
                        this.instrumentedType = instrumentedType;
1✔
5855
                    }
1✔
5856

5857
                    /**
5858
                     * {@inheritDoc}
5859
                     */
5860
                    public FieldDescription.InDefinedShape get(int index) {
UNCOV
5861
                        return instrumentedType.getDeclaredFields().get(index);
×
5862
                    }
5863

5864
                    /**
5865
                     * {@inheritDoc}
5866
                     */
5867
                    public int size() {
UNCOV
5868
                        return instrumentedType.getDeclaredFields().size();
×
5869
                    }
5870
                }
5871

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

5878
                    /**
5879
                     * A context registry to register the lazily created implementation context to.
5880
                     */
5881
                    private final ContextRegistry contextRegistry;
5882

5883
                    /**
5884
                     * The writer flags being used.
5885
                     */
5886
                    private final int writerFlags;
5887

5888
                    /**
5889
                     * The reader flags being used.
5890
                     */
5891
                    private final int readerFlags;
5892

5893
                    /**
5894
                     * The implementation context to use or {@code null} if the context is not yet initialized.
5895
                     */
5896
                    @UnknownNull
5897
                    private Implementation.Context.ExtractableView implementationContext;
5898

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

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

5942
                    @Override
5943
                    @MaybeNull
5944
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5945
                        return annotationRetention.isEnabled()
×
5946
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
UNCOV
5947
                                : IGNORE_ANNOTATION;
×
5948
                    }
5949

5950
                    @Override
5951
                    @MaybeNull
5952
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5953
                        return annotationRetention.isEnabled()
1✔
5954
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5955
                                : IGNORE_ANNOTATION;
1✔
5956
                    }
5957

5958
                    @Override
5959
                    protected void onAfterAttributes() {
5960
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5961
                    }
1✔
5962

5963
                    @Override
5964
                    protected void onVisitEnd() {
5965
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
5966
                        cv.visitEnd();
1✔
5967
                    }
1✔
5968

5969
                    /**
5970
                     * {@inheritDoc}
5971
                     */
5972
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
5973
                        /* do nothing */
5974
                    }
1✔
5975
                }
5976
            }
5977
        }
5978

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

5987
            /**
5988
             * The method pool to use.
5989
             */
5990
            private final MethodPool methodPool;
5991

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

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

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

6182
            /**
6183
             * A class visitor that applies the subclass creation as a wrapper.
6184
             */
6185
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6186

6187
                /**
6188
                 * The implementation context to apply.
6189
                 */
6190
                private final Implementation.Context.ExtractableView implementationContext;
6191

6192
                /**
6193
                 * The underlying module information or {@code null} if no such information is provided.
6194
                 */
6195
                @MaybeNull
6196
                private final ModuleDescription moduleDescription;
6197

6198
                /**
6199
                 * The declared types that have been visited.
6200
                 */
6201
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6202

6203
                /**
6204
                 * The signatures of all fields that were explicitly visited.
6205
                 */
6206
                private final Set<SignatureKey> visitedFields = new HashSet<SignatureKey>();
1✔
6207

6208
                /**
6209
                 * The signature of all methods that were explicitly visited.
6210
                 */
6211
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6212

6213
                /**
6214
                 * Creates a new wrapper visitor.
6215
                 *
6216
                 * @param classVisitor          The class visitor being wrapped.
6217
                 * @param implementationContext The implementation context to apply.
6218
                 * @param moduleDescription     The underlying module information or {@code null} if no such information is provided.
6219
                 */
6220
                protected CreationClassVisitor(ClassVisitor classVisitor,
6221
                                               Implementation.Context.ExtractableView implementationContext,
6222
                                               @MaybeNull ModuleDescription moduleDescription) {
1✔
6223
                    super(OpenedClassReader.ASM_API, classVisitor);
1✔
6224
                    this.implementationContext = implementationContext;
1✔
6225
                    this.moduleDescription = moduleDescription;
1✔
6226
                }
1✔
6227

6228
                @Override
6229
                protected void onModule() {
6230
                    if (moduleDescription != null) {
1✔
UNCOV
6231
                        moduleDescription.accept(cv);
×
6232
                    }
6233
                }
1✔
6234

6235
                @Override
6236
                @MaybeNull
6237
                protected ModuleVisitor onVisitModule(String name, int modifiers, @MaybeNull String version) {
6238
                    return moduleDescription == null ? null : new PatchingModuleVisitor(cv.visitModule(moduleDescription.getActualName(),
×
6239
                            moduleDescription.getModifiers(),
×
UNCOV
6240
                            moduleDescription.getVersion()), moduleDescription);
×
6241
                }
6242

6243
                @Override
6244
                protected void onAfterAttributes() {
6245
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6246
                }
1✔
6247

6248
                @Override
6249
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6250
                    declaredTypes.add(internalName);
×
6251
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
UNCOV
6252
                }
×
6253

6254
                @Override
6255
                @MaybeNull
6256
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6257
                    visitedFields.add(new SignatureKey(name, descriptor));
×
UNCOV
6258
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6259
                }
6260

6261
                @Override
6262
                @MaybeNull
6263
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
6264
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
UNCOV
6265
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6266
                }
6267

6268
                @Override
6269
                protected void onVisitEnd() {
6270
                    for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6271
                        if (!declaredTypes.contains(typeDescription.getInternalName())) {
×
6272
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
6273
                                    typeDescription.isMemberType()
×
6274
                                            ? instrumentedType.getInternalName()
×
6275
                                            : NO_REFERENCE,
×
6276
                                    typeDescription.isAnonymousType()
×
6277
                                            ? NO_REFERENCE
×
6278
                                            : typeDescription.getSimpleName(),
×
UNCOV
6279
                                    typeDescription.getModifiers());
×
6280
                        }
UNCOV
6281
                    }
×
6282
                    for (FieldDescription fieldDescription : fields) {
1✔
6283
                        if (!visitedFields.contains(new SignatureKey(fieldDescription.getName(), fieldDescription.getDescriptor()))) {
×
UNCOV
6284
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
×
6285
                        }
UNCOV
6286
                    }
×
6287
                    for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6288
                        if (!visitedMethods.contains(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()))) {
1✔
6289
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
6290
                        }
6291
                    }
1✔
6292
                    implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6293
                            methodPool,
1✔
6294
                            annotationValueFilterFactory), cv, annotationValueFilterFactory);
6295
                    super.onVisitEnd();
1✔
6296
                }
1✔
6297
            }
6298

6299
            /**
6300
             * A class visitor that applies the subclass creation as a wrapper.
6301
             */
6302
            protected static class PatchingModuleVisitor extends ModuleVisitor {
6303

6304
                /**
6305
                 * The internal name of the main class or {@code null} if no main class is defined.
6306
                 */
6307
                @MaybeNull
6308
                private String mainClass;
6309

6310
                /**
6311
                 * The internal name of all packages of the module.
6312
                 */
6313
                private final Set<String> packages;
6314

6315
                /**
6316
                 * A mapping of required modules to their configuration.
6317
                 */
6318
                private final Map<String, ModuleDescription.Requires> requires;
6319

6320
                /**
6321
                 * A mapping of the internal names of exported packages to their configuration.
6322
                 */
6323
                private final Map<String, ModuleDescription.Exports> exports;
6324

6325
                /**
6326
                 * A mapping of the internal names of opened packages to their configuration.
6327
                 */
6328
                private final Map<String, ModuleDescription.Opens> opens;
6329

6330
                /**
6331
                 * A collection of internal names of used services.
6332
                 */
6333
                private final Set<String> uses;
6334

6335
                /**
6336
                 * A mapping of the internal names of provided services to the internal names of the provided implementations.
6337
                 */
6338
                private final Map<String, Set<String>> provides;
6339

6340
                /**
6341
                 * Creates a module visitor that patches the module implementation.
6342
                 *
6343
                 * @param moduleVisitor     The module visitor to which the data is delegated to.
6344
                 * @param moduleDescription A description of the module.
6345
                 */
6346
                protected PatchingModuleVisitor(ModuleVisitor moduleVisitor, ModuleDescription moduleDescription) {
6347
                    super(OpenedClassReader.ASM_API, moduleVisitor);
×
6348
                    mainClass = moduleDescription.getMainClass();
×
6349
                    if (mainClass != null) {
×
UNCOV
6350
                        mainClass = mainClass.replace('.', '/');
×
6351
                    }
6352
                    packages = new LinkedHashSet<String>();
×
6353
                    for (String aPackage : moduleDescription.getPackages()) {
×
6354
                        packages.add(aPackage.replace('.', '/'));
×
6355
                    }
×
6356
                    requires = new LinkedHashMap<String, ModuleDescription.Requires>(moduleDescription.getRequires());
×
6357
                    exports = new LinkedHashMap<String, ModuleDescription.Exports>();
×
6358
                    for (Map.Entry<String, ModuleDescription.Exports> entry : moduleDescription.getExports().entrySet()) {
×
6359
                        exports.put(entry.getKey().replace('.', '/'), entry.getValue());
×
6360
                    }
×
6361
                    opens = new LinkedHashMap<String, ModuleDescription.Opens>();
×
6362
                    for (Map.Entry<String, ModuleDescription.Opens> entry : moduleDescription.getOpens().entrySet()) {
×
6363
                        opens.put(entry.getKey().replace('.', '/'), entry.getValue());
×
6364
                    }
×
6365
                    uses = new LinkedHashSet<String>();
×
6366
                    for (String use : moduleDescription.getUses()) {
×
6367
                        uses.add(use.replace('.', '/'));
×
6368
                    }
×
6369
                    provides = new LinkedHashMap<String, Set<String>>();
×
6370
                    for (Map.Entry<String, ModuleDescription.Provides> entry : moduleDescription.getProvides().entrySet()) {
×
6371
                        Set<String> providers = new LinkedHashSet<String>();
×
6372
                        for (String provider : entry.getValue().getProviders()) {
×
6373
                            providers.add(provider.replace('.', '/'));
×
6374
                        }
×
6375
                        provides.put(entry.getKey().replace('.', '/'), providers);
×
6376
                    }
×
UNCOV
6377
                }
×
6378

6379
                @Override
6380
                public void visitMainClass(String mainClass) {
6381
                    if (this.mainClass != null) {
×
6382
                        super.visitMainClass(this.mainClass);
×
UNCOV
6383
                        this.mainClass = null;
×
6384
                    }
UNCOV
6385
                }
×
6386

6387
                @Override
6388
                public void visitPackage(String aPackage) {
6389
                    super.visitPackage(aPackage);
×
6390
                    packages.remove(aPackage);
×
UNCOV
6391
                }
×
6392

6393
                @Override
6394
                public void visitRequire(String module, int modifiers, @MaybeNull String version) {
6395
                    ModuleDescription.Requires requires = this.requires.remove(module);
×
6396
                    if (requires != null) {
×
UNCOV
6397
                        super.visitRequire(module, requires.getModifiers(), requires.getVersion());
×
6398
                    } else {
UNCOV
6399
                        super.visitRequire(module, modifiers, version);
×
6400
                    }
UNCOV
6401
                }
×
6402

6403
                @Override
6404
                public void visitExport(String aPackage, int modifiers, @MaybeNull String... module) {
6405
                    ModuleDescription.Exports exports = this.exports.remove(aPackage);
×
6406
                    if (exports != null) {
×
UNCOV
6407
                        super.visitExport(aPackage, exports.getModifiers(), exports.getTargets().isEmpty()
×
6408
                                ? null
UNCOV
6409
                                : exports.getTargets().toArray(new String[0]));
×
6410
                    } else {
UNCOV
6411
                        super.visitExport(aPackage, modifiers, module);
×
6412
                    }
UNCOV
6413
                }
×
6414

6415
                @Override
6416
                public void visitOpen(String aPackage, int modifiers, @MaybeNull String... module) {
6417
                    ModuleDescription.Opens opens = this.opens.remove(aPackage);
×
6418
                    if (opens != null) {
×
UNCOV
6419
                        super.visitOpen(aPackage, opens.getModifiers(), opens.getTargets().isEmpty()
×
6420
                                ? null
UNCOV
6421
                                : opens.getTargets().toArray(new String[0]));
×
6422
                    } else {
UNCOV
6423
                        super.visitOpen(aPackage, modifiers, module);
×
6424
                    }
UNCOV
6425
                }
×
6426

6427
                @Override
6428
                public void visitUse(String service) {
6429
                    uses.remove(service);
×
6430
                    super.visitUse(service);
×
UNCOV
6431
                }
×
6432

6433
                @Override
6434
                public void visitProvide(String service, String... provider) {
6435
                    Set<String> providers = this.provides.remove(service);
×
6436
                    if (providers != null) {
×
UNCOV
6437
                        super.visitProvide(service, providers.toArray(new String[0]));
×
6438
                    } else {
UNCOV
6439
                        super.visitProvide(service, provider);
×
6440
                    }
UNCOV
6441
                }
×
6442

6443
                @Override
6444
                public void visitEnd() {
6445
                    if (mainClass != null) {
×
UNCOV
6446
                        super.visitMainClass(mainClass);
×
6447
                    }
6448
                    for (String aPackage : packages) {
×
6449
                        super.visitPackage(aPackage);
×
6450
                    }
×
6451
                    for (Map.Entry<String, ModuleDescription.Requires> entry : requires.entrySet()) {
×
6452
                        super.visitRequire(entry.getKey(), entry.getValue().getModifiers(), entry.getValue().getVersion());
×
6453
                    }
×
6454
                    for (Map.Entry<String, ModuleDescription.Exports> entry : exports.entrySet()) {
×
6455
                        super.visitExport(entry.getKey(),
×
6456
                                entry.getValue().getModifiers(),
×
6457
                                entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
×
6458
                    }
×
6459
                    for (Map.Entry<String, ModuleDescription.Opens> entry : opens.entrySet()) {
×
6460
                        super.visitOpen(entry.getKey(),
×
6461
                                entry.getValue().getModifiers(),
×
6462
                                entry.getValue().getTargets().isEmpty() ? null : entry.getValue().getTargets().toArray(new String[0]));
×
6463
                    }
×
6464
                    for (String use : uses) {
×
6465
                        super.visitUse(use);
×
6466
                    }
×
6467
                    for (Map.Entry<String, Set<String>> entry : provides.entrySet()) {
×
6468
                        super.visitProvide(entry.getKey(), entry.getValue().isEmpty() ? null : entry.getValue().toArray(new String[0]));
×
6469
                    }
×
6470
                    super.visitEnd();
×
UNCOV
6471
                }
×
6472
            }
6473

6474
            /**
6475
             * A context class visitor based on an {@link Implementation.Context}.
6476
             */
6477
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6478

6479
                /**
6480
                 * The implementation context to use.
6481
                 */
6482
                private final Implementation.Context.ExtractableView implementationContext;
6483

6484
                /**
6485
                 * Creates a context class loader based on an {@link Implementation.Context}.
6486
                 *
6487
                 * @param classVisitor          The class visitor to delegate to.
6488
                 * @param implementationContext The implementation context to use.
6489
                 */
6490
                protected ImplementationContextClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6491
                    super(classVisitor);
1✔
6492
                    this.implementationContext = implementationContext;
1✔
6493
                }
1✔
6494

6495
                @Override
6496
                public List<DynamicType> getAuxiliaryTypes() {
6497
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6498
                }
6499

6500
                @Override
6501
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6502
                    return loadedTypeInitializer;
1✔
6503
                }
6504
            }
6505
        }
6506

6507
        /**
6508
         * An action to write a class file to the dumping location.
6509
         */
6510
        @HashCodeAndEqualsPlugin.Enhance
6511
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6512

6513
            /**
6514
             * Indicates that nothing is returned from this action.
6515
             */
6516
            @AlwaysNull
6517
            private static final Void NOTHING = null;
1✔
6518

6519
            /**
6520
             * The target folder for writing the class file to.
6521
             */
6522
            private final String target;
6523

6524
            /**
6525
             * The instrumented type.
6526
             */
6527
            private final TypeDescription instrumentedType;
6528

6529
            /**
6530
             * {@code true} if the dumped class file is an input to a class transformation.
6531
             */
6532
            private final boolean original;
6533

6534
            /**
6535
             * The suffix to append to the dumped class file.
6536
             */
6537
            private final long suffix;
6538

6539
            /**
6540
             * The type's binary representation.
6541
             */
6542
            private final byte[] binaryRepresentation;
6543

6544
            /**
6545
             * Creates a new class dump action.
6546
             *
6547
             * @param target               The target folder for writing the class file to.
6548
             * @param instrumentedType     The instrumented type.
6549
             * @param original             {@code true} if the dumped class file is an input to a class transformation.
6550
             * @param suffix               The suffix to append to the dumped class file.
6551
             * @param binaryRepresentation The type's binary representation.
6552
             */
6553
            protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
1✔
6554
                this.target = target;
1✔
6555
                this.instrumentedType = instrumentedType;
1✔
6556
                this.original = original;
1✔
6557
                this.suffix = suffix;
1✔
6558
                this.binaryRepresentation = binaryRepresentation;
1✔
6559
            }
1✔
6560

6561
            /**
6562
             * {@inheritDoc}
6563
             */
6564
            public Void run() throws Exception {
6565
                OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
1✔
6566
                        + (original ? "-original." : ".")
6567
                        + suffix
6568
                        + ".class"));
6569
                try {
6570
                    outputStream.write(binaryRepresentation);
1✔
6571
                    return NOTHING;
1✔
6572
                } finally {
6573
                    outputStream.close();
1✔
6574
                }
6575
            }
6576

6577
            /**
6578
             * A dispatcher for dumping class files to the file system.
6579
             */
6580
            protected interface Dispatcher {
6581

6582
                /**
6583
                 * Dumps a class file to the file system.
6584
                 *
6585
                 * @param instrumentedType     The type to dump.
6586
                 * @param original             {@code true} if the class file is in its original state.
6587
                 * @param binaryRepresentation The class file's binary representation.
6588
                 */
6589
                void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
6590

6591
                /**
6592
                 * A disabled dispatcher that does not dump any class files.
6593
                 */
6594
                enum Disabled implements Dispatcher {
1✔
6595

6596
                    /**
6597
                     * The singleton instance.
6598
                     */
6599
                    INSTANCE;
1✔
6600

6601
                    /**
6602
                     * {@inheritDoc}
6603
                     */
6604
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6605
                        /* do nothing */
6606
                    }
1✔
6607
                }
6608

6609
                /**
6610
                 * An enabled dispatcher that dumps class files to a given folder.
6611
                 */
6612
                @HashCodeAndEqualsPlugin.Enhance
6613
                class Enabled implements Dispatcher {
6614

6615
                    /**
6616
                     * The folder to write class files to.
6617
                     */
6618
                    private final String folder;
6619

6620
                    /**
6621
                     * The timestamp to append.
6622
                     */
6623
                    private final long timestamp;
6624

6625
                    /**
6626
                     * Creates a new dispatcher for dumping class files.
6627
                     *
6628
                     * @param folder    The folder to write class files to.
6629
                     * @param timestamp The timestamp to append.
6630
                     */
6631
                    protected Enabled(String folder, long timestamp) {
1✔
6632
                        this.folder = folder;
1✔
6633
                        this.timestamp = timestamp;
1✔
6634
                    }
1✔
6635

6636
                    /**
6637
                     * {@inheritDoc}
6638
                     */
6639
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6640
                        try {
6641
                            doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
1✔
6642
                        } catch (Exception exception) {
×
UNCOV
6643
                            exception.printStackTrace();
×
6644
                        }
1✔
6645
                    }
1✔
6646
                }
6647
            }
6648
        }
6649
    }
6650
}
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