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

raphw / byte-buddy / #764

05 Apr 2025 05:32PM UTC coverage: 85.139% (-0.004%) from 85.143%
#764

push

raphw
Remove forgotten line.

29373 of 34500 relevant lines covered (85.14%)

0.85 hits per line

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

81.09
/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java
1
/*
2
 * Copyright 2014 - Present Rafael Winterhalter
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *     http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package net.bytebuddy.dynamic.scaffold;
17

18
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
19
import net.bytebuddy.ClassFileVersion;
20
import net.bytebuddy.asm.AsmVisitorWrapper;
21
import net.bytebuddy.build.AccessControllerPlugin;
22
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
23
import net.bytebuddy.description.annotation.AnnotationList;
24
import net.bytebuddy.description.annotation.AnnotationValue;
25
import net.bytebuddy.description.field.FieldDescription;
26
import net.bytebuddy.description.field.FieldList;
27
import net.bytebuddy.description.method.MethodDescription;
28
import net.bytebuddy.description.method.MethodList;
29
import net.bytebuddy.description.method.ParameterDescription;
30
import net.bytebuddy.description.method.ParameterList;
31
import net.bytebuddy.description.modifier.ModifierContributor;
32
import net.bytebuddy.description.modifier.Visibility;
33
import net.bytebuddy.description.type.*;
34
import net.bytebuddy.dynamic.ClassFileLocator;
35
import net.bytebuddy.dynamic.DynamicType;
36
import net.bytebuddy.dynamic.TypeResolutionStrategy;
37
import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
38
import net.bytebuddy.dynamic.scaffold.inline.RebaseImplementationTarget;
39
import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget;
40
import net.bytebuddy.implementation.Implementation;
41
import net.bytebuddy.implementation.LoadedTypeInitializer;
42
import net.bytebuddy.implementation.attribute.*;
43
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
44
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
45
import net.bytebuddy.implementation.bytecode.StackManipulation;
46
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
47
import net.bytebuddy.implementation.bytecode.constant.DefaultValue;
48
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
49
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
50
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
51
import net.bytebuddy.pool.TypePool;
52
import net.bytebuddy.utility.AsmClassReader;
53
import net.bytebuddy.utility.AsmClassWriter;
54
import net.bytebuddy.utility.CompoundList;
55
import net.bytebuddy.utility.OpenedClassReader;
56
import net.bytebuddy.utility.nullability.AlwaysNull;
57
import net.bytebuddy.utility.nullability.MaybeNull;
58
import net.bytebuddy.utility.nullability.UnknownNull;
59
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
60
import net.bytebuddy.utility.visitor.ContextClassVisitor;
61
import net.bytebuddy.utility.visitor.MetadataAwareClassVisitor;
62
import org.objectweb.asm.*;
63
import org.objectweb.asm.commons.ClassRemapper;
64
import org.objectweb.asm.commons.Remapper;
65
import org.objectweb.asm.commons.SimpleRemapper;
66

67
import javax.annotation.Nonnull;
68
import java.io.File;
69
import java.io.FileOutputStream;
70
import java.io.IOException;
71
import java.io.OutputStream;
72
import java.security.PrivilegedAction;
73
import java.security.PrivilegedExceptionAction;
74
import java.util.*;
75

76
import static net.bytebuddy.matcher.ElementMatchers.*;
77

78
/**
79
 * A type writer is a utility for writing an actual class file using the ASM library.
80
 *
81
 * @param <T> The best known loaded type for the dynamically created type.
82
 */
83
public interface TypeWriter<T> {
84

85
    /**
86
     * A system property that indicates a folder for Byte Buddy to dump class files of all types that it creates.
87
     * If this property is not set, Byte Buddy does not dump any class files. This property is only read a single
88
     * time which is why it must be set on application start-up.
89
     */
90
    String DUMP_PROPERTY = "net.bytebuddy.dump";
91

92
    /**
93
     * Creates the dynamic type that is described by this type writer.
94
     *
95
     * @param typeResolver The type resolution strategy to use.
96
     * @return An unloaded dynamic type that describes the created type.
97
     */
98
    DynamicType.Unloaded<T> make(TypeResolutionStrategy.Resolved typeResolver);
99

100
    /**
101
     * Wraps another ASM class visitor with a visitor that represents this ASM class writer.
102
     *
103
     * @param classVisitor The class visitor to wrap.
104
     * @param writerFlags  The ASM writer flags to consider.
105
     * @param readerFlags  The ASM reader flags to consider.
106
     * @return The supplied class visitor wrapped by this type writer.
107
     */
108
    ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags);
109

110
    /**
111
     * An field pool that allows a lookup for how to implement a field.
112
     */
113
    interface FieldPool {
114

115
        /**
116
         * Looks up a handler entry for a given field.
117
         *
118
         * @param fieldDescription The field being processed.
119
         * @return A handler entry for the given field.
120
         */
121
        Record target(FieldDescription fieldDescription);
122

123
        /**
124
         * An entry of a field pool that describes how a field is implemented.
125
         *
126
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.FieldPool
127
         */
128
        interface Record {
129

130
            /**
131
             * Determines if this record is implicit, i.e is not defined by a {@link FieldPool}.
132
             *
133
             * @return {@code true} if this record is implicit.
134
             */
135
            boolean isImplicit();
136

137
            /**
138
             * Returns the field that this record represents.
139
             *
140
             * @return The field that this record represents.
141
             */
142
            FieldDescription getField();
143

144
            /**
145
             * Returns the field attribute appender for a given field.
146
             *
147
             * @return The attribute appender to be applied on the given field.
148
             */
149
            FieldAttributeAppender getFieldAppender();
150

151
            /**
152
             * Resolves the default value that this record represents. This is not possible for implicit records.
153
             *
154
             * @param defaultValue The default value that was defined previously or {@code null} if no default value is defined.
155
             * @return The default value for the represented field or {@code null} if no default value is to be defined.
156
             */
157
            @MaybeNull
158
            Object resolveDefault(@MaybeNull Object defaultValue);
159

160
            /**
161
             * Writes this entry to a given class visitor.
162
             *
163
             * @param classVisitor                 The class visitor to which this entry is to be written to.
164
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
165
             */
166
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
167

168
            /**
169
             * Applies this record to a field visitor. This is not possible for implicit records.
170
             *
171
             * @param fieldVisitor                 The field visitor onto which this record is to be applied.
172
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
173
             */
174
            void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
175

176
            /**
177
             * A record for a simple field without a default value where all of the field's declared annotations are appended.
178
             */
179
            @HashCodeAndEqualsPlugin.Enhance
180
            class ForImplicitField implements Record {
181

182
                /**
183
                 * The implemented field.
184
                 */
185
                private final FieldDescription fieldDescription;
186

187
                /**
188
                 * Creates a new record for a simple field.
189
                 *
190
                 * @param fieldDescription The described field.
191
                 */
192
                public ForImplicitField(FieldDescription fieldDescription) {
1✔
193
                    this.fieldDescription = fieldDescription;
1✔
194
                }
1✔
195

196
                /**
197
                 * {@inheritDoc}
198
                 */
199
                public boolean isImplicit() {
200
                    return true;
1✔
201
                }
202

203
                /**
204
                 * {@inheritDoc}
205
                 */
206
                public FieldDescription getField() {
207
                    return fieldDescription;
1✔
208
                }
209

210
                /**
211
                 * {@inheritDoc}
212
                 */
213
                public FieldAttributeAppender getFieldAppender() {
214
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
1✔
215
                }
216

217
                /**
218
                 * {@inheritDoc}
219
                 */
220
                public Object resolveDefault(@MaybeNull Object defaultValue) {
221
                    throw new IllegalStateException("An implicit field record does not expose a default value: " + this);
1✔
222
                }
223

224
                /**
225
                 * {@inheritDoc}
226
                 */
227
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
228
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
229
                            fieldDescription.getInternalName(),
1✔
230
                            fieldDescription.getDescriptor(),
1✔
231
                            fieldDescription.getGenericSignature(),
1✔
232
                            FieldDescription.NO_DEFAULT_VALUE);
233
                    if (fieldVisitor != null) {
1✔
234
                        FieldAttributeAppender.ForInstrumentedField.INSTANCE.apply(fieldVisitor,
1✔
235
                                fieldDescription,
236
                                annotationValueFilterFactory.on(fieldDescription));
1✔
237
                        fieldVisitor.visitEnd();
1✔
238
                    }
239
                }
1✔
240

241
                /**
242
                 * {@inheritDoc}
243
                 */
244
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
245
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
246
                }
247
            }
248

249
            /**
250
             * A record for a rich field with attributes and a potential default value.
251
             */
252
            @HashCodeAndEqualsPlugin.Enhance
253
            class ForExplicitField implements Record {
254

255
                /**
256
                 * The attribute appender for the field.
257
                 */
258
                private final FieldAttributeAppender attributeAppender;
259

260
                /**
261
                 * The field's default value.
262
                 */
263
                @MaybeNull
264
                @HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
265
                private final Object defaultValue;
266

267
                /**
268
                 * The implemented field.
269
                 */
270
                private final FieldDescription fieldDescription;
271

272
                /**
273
                 * Creates a record for a rich field.
274
                 *
275
                 * @param attributeAppender The attribute appender for the field.
276
                 * @param defaultValue      The field's default value.
277
                 * @param fieldDescription  The implemented field.
278
                 */
279
                public ForExplicitField(FieldAttributeAppender attributeAppender,
280
                                        @MaybeNull Object defaultValue,
281
                                        FieldDescription fieldDescription) {
1✔
282
                    this.attributeAppender = attributeAppender;
1✔
283
                    this.defaultValue = defaultValue;
1✔
284
                    this.fieldDescription = fieldDescription;
1✔
285
                }
1✔
286

287
                /**
288
                 * {@inheritDoc}
289
                 */
290
                public boolean isImplicit() {
291
                    return false;
1✔
292
                }
293

294
                /**
295
                 * {@inheritDoc}
296
                 */
297
                public FieldDescription getField() {
298
                    return fieldDescription;
1✔
299
                }
300

301
                /**
302
                 * {@inheritDoc}
303
                 */
304
                public FieldAttributeAppender getFieldAppender() {
305
                    return attributeAppender;
1✔
306
                }
307

308
                /**
309
                 * {@inheritDoc}
310
                 */
311
                @MaybeNull
312
                public Object resolveDefault(@MaybeNull Object defaultValue) {
313
                    return this.defaultValue == null
1✔
314
                            ? defaultValue
315
                            : this.defaultValue;
316
                }
317

318
                /**
319
                 * {@inheritDoc}
320
                 */
321
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
322
                    FieldVisitor fieldVisitor = classVisitor.visitField(fieldDescription.getActualModifiers(),
1✔
323
                            fieldDescription.getInternalName(),
1✔
324
                            fieldDescription.getDescriptor(),
1✔
325
                            fieldDescription.getGenericSignature(),
1✔
326
                            resolveDefault(FieldDescription.NO_DEFAULT_VALUE));
1✔
327
                    if (fieldVisitor != null) {
1✔
328
                        attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
329
                        fieldVisitor.visitEnd();
1✔
330
                    }
331
                }
1✔
332

333
                /**
334
                 * {@inheritDoc}
335
                 */
336
                public void apply(FieldVisitor fieldVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
337
                    attributeAppender.apply(fieldVisitor, fieldDescription, annotationValueFilterFactory.on(fieldDescription));
1✔
338
                }
1✔
339
            }
340
        }
341

342
        /**
343
         * A field pool that does not allow any look ups.
344
         */
345
        enum Disabled implements FieldPool {
1✔
346

347
            /**
348
             * The singleton instance.
349
             */
350
            INSTANCE;
1✔
351

352
            /**
353
             * {@inheritDoc}
354
             */
355
            public Record target(FieldDescription fieldDescription) {
356
                throw new IllegalStateException("Cannot look up field from disabled pool");
1✔
357
            }
358
        }
359
    }
360

361
    /**
362
     * An method pool that allows a lookup for how to implement a method.
363
     */
364
    interface MethodPool {
365

366
        /**
367
         * Looks up a handler entry for a given method.
368
         *
369
         * @param methodDescription The method being processed.
370
         * @return A handler entry for the given method.
371
         */
372
        Record target(MethodDescription methodDescription);
373

374
        /**
375
         * An entry of a method pool that describes how a method is implemented.
376
         *
377
         * @see net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool
378
         */
379
        interface Record {
380

381
            /**
382
             * Returns the sort of this method instrumentation.
383
             *
384
             * @return The sort of this method instrumentation.
385
             */
386
            Sort getSort();
387

388
            /**
389
             * Returns the method that is implemented where the returned method resembles a potential transformation. An implemented
390
             * method is only defined if a method is not {@link Record.Sort#SKIPPED}.
391
             *
392
             * @return The implemented method.
393
             */
394
            MethodDescription getMethod();
395

396
            /**
397
             * The visibility to enforce for this method.
398
             *
399
             * @return The visibility to enforce for this method.
400
             */
401
            Visibility getVisibility();
402

403
            /**
404
             * Prepends the given method appender to this entry.
405
             *
406
             * @param byteCodeAppender The byte code appender to prepend.
407
             * @return This entry with the given code prepended.
408
             */
409
            Record prepend(ByteCodeAppender byteCodeAppender);
410

411
            /**
412
             * Applies this method entry. This method can always be called and might be a no-op.
413
             *
414
             * @param classVisitor                 The class visitor to which this entry should be applied.
415
             * @param implementationContext        The implementation context to which this entry should be applied.
416
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
417
             */
418
            void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
419

420
            /**
421
             * 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
422
             * {@link Record.Sort#SKIPPED}.
423
             *
424
             * @param methodVisitor The method visitor to which this entry should be applied.
425
             */
426
            void applyHead(MethodVisitor methodVisitor);
427

428
            /**
429
             * 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
430
             * entry is {@link Record.Sort#IMPLEMENTED}.
431
             *
432
             * @param methodVisitor                The method visitor to which this entry should be applied.
433
             * @param implementationContext        The implementation context to which this entry should be applied.
434
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
435
             */
436
            void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory);
437

438
            /**
439
             * 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
440
             * entry is {@link Record.Sort#DEFINED}.
441
             *
442
             * @param methodVisitor                The method visitor to which this entry should be applied.
443
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
444
             */
445
            void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
446

447
            /**
448
             * 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
449
             * entry is {@link Record.Sort#IMPLEMENTED}.
450
             *
451
             * @param methodVisitor         The method visitor to which this entry should be applied.
452
             * @param implementationContext The implementation context to which this entry should be applied.
453
             * @return The size requirements of the implemented code.
454
             */
455
            ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext);
456

457
            /**
458
             * The sort of an entry.
459
             */
460
            enum Sort {
1✔
461

462
                /**
463
                 * Describes a method that should not be implemented or retained in its original state.
464
                 */
465
                SKIPPED(false, false),
1✔
466

467
                /**
468
                 * Describes a method that should be defined but is abstract or native, i.e. does not define any byte code.
469
                 */
470
                DEFINED(true, false),
1✔
471

472
                /**
473
                 * Describes a method that is implemented in byte code.
474
                 */
475
                IMPLEMENTED(true, true);
1✔
476

477
                /**
478
                 * Indicates if this sort defines a method, with or without byte code.
479
                 */
480
                private final boolean define;
481

482
                /**
483
                 * Indicates if this sort defines byte code.
484
                 */
485
                private final boolean implement;
486

487
                /**
488
                 * Creates a new sort.
489
                 *
490
                 * @param define    Indicates if this sort defines a method, with or without byte code.
491
                 * @param implement Indicates if this sort defines byte code.
492
                 */
493
                Sort(boolean define, boolean implement) {
1✔
494
                    this.define = define;
1✔
495
                    this.implement = implement;
1✔
496
                }
1✔
497

498
                /**
499
                 * Indicates if this sort defines a method, with or without byte code.
500
                 *
501
                 * @return {@code true} if this sort defines a method, with or without byte code.
502
                 */
503
                public boolean isDefined() {
504
                    return define;
1✔
505
                }
506

507
                /**
508
                 * Indicates if this sort defines byte code.
509
                 *
510
                 * @return {@code true} if this sort defines byte code.
511
                 */
512
                public boolean isImplemented() {
513
                    return implement;
1✔
514
                }
515
            }
516

517
            /**
518
             * A canonical implementation of a method that is not declared but inherited by the instrumented type.
519
             */
520
            @HashCodeAndEqualsPlugin.Enhance
521
            class ForNonImplementedMethod implements Record {
522

523
                /**
524
                 * The undefined method.
525
                 */
526
                private final MethodDescription methodDescription;
527

528
                /**
529
                 * Creates a new undefined record.
530
                 *
531
                 * @param methodDescription The undefined method.
532
                 */
533
                public ForNonImplementedMethod(MethodDescription methodDescription) {
1✔
534
                    this.methodDescription = methodDescription;
1✔
535
                }
1✔
536

537
                /**
538
                 * {@inheritDoc}
539
                 */
540
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
541
                    /* do nothing */
542
                }
1✔
543

544
                /**
545
                 * {@inheritDoc}
546
                 */
547
                public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
548
                    throw new IllegalStateException("Cannot apply body for non-implemented method on " + methodDescription);
1✔
549
                }
550

551
                /**
552
                 * {@inheritDoc}
553
                 */
554
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
555
                    /* do nothing */
556
                }
1✔
557

558
                /**
559
                 * {@inheritDoc}
560
                 */
561
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
562
                    throw new IllegalStateException("Cannot apply code for non-implemented method on " + methodDescription);
×
563
                }
564

565
                /**
566
                 * {@inheritDoc}
567
                 */
568
                public void applyHead(MethodVisitor methodVisitor) {
569
                    throw new IllegalStateException("Cannot apply head for non-implemented method on " + methodDescription);
1✔
570
                }
571

572
                /**
573
                 * {@inheritDoc}
574
                 */
575
                public MethodDescription getMethod() {
576
                    return methodDescription;
1✔
577
                }
578

579
                /**
580
                 * {@inheritDoc}
581
                 */
582
                public Visibility getVisibility() {
583
                    return methodDescription.getVisibility();
×
584
                }
585

586
                /**
587
                 * {@inheritDoc}
588
                 */
589
                public Sort getSort() {
590
                    return Sort.SKIPPED;
1✔
591
                }
592

593
                /**
594
                 * {@inheritDoc}
595
                 */
596
                public Record prepend(ByteCodeAppender byteCodeAppender) {
597
                    return new ForDefinedMethod.WithBody(methodDescription, new ByteCodeAppender.Compound(byteCodeAppender,
1✔
598
                            new ByteCodeAppender.Simple(DefaultValue.of(methodDescription.getReturnType()), MethodReturn.of(methodDescription.getReturnType()))));
1✔
599
                }
600
            }
601

602
            /**
603
             * A base implementation of an abstract entry that defines a method.
604
             */
605
            abstract class ForDefinedMethod implements Record {
1✔
606

607
                /**
608
                 * {@inheritDoc}
609
                 */
610
                public void apply(ClassVisitor classVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
611
                    MethodVisitor methodVisitor = classVisitor.visitMethod(getMethod().getActualModifiers(getSort().isImplemented(), getVisibility()),
1✔
612
                            getMethod().getInternalName(),
1✔
613
                            getMethod().getDescriptor(),
1✔
614
                            getMethod().getGenericSignature(),
1✔
615
                            getMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
616
                    if (methodVisitor != null) {
1✔
617
                        ParameterList<?> parameterList = getMethod().getParameters();
1✔
618
                        if (parameterList.hasExplicitMetaData()) {
1✔
619
                            for (ParameterDescription parameterDescription : parameterList) {
1✔
620
                                methodVisitor.visitParameter(parameterDescription.getName(), parameterDescription.getModifiers());
1✔
621
                            }
1✔
622
                        }
623
                        applyHead(methodVisitor);
1✔
624
                        applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
625
                        methodVisitor.visitEnd();
1✔
626
                    }
627
                }
1✔
628

629
                /**
630
                 * Describes an entry that defines a method as byte code.
631
                 */
632
                @HashCodeAndEqualsPlugin.Enhance
633
                public static class WithBody extends ForDefinedMethod {
634

635
                    /**
636
                     * The implemented method.
637
                     */
638
                    private final MethodDescription methodDescription;
639

640
                    /**
641
                     * The byte code appender to apply.
642
                     */
643
                    private final ByteCodeAppender byteCodeAppender;
644

645
                    /**
646
                     * The method attribute appender to apply.
647
                     */
648
                    private final MethodAttributeAppender methodAttributeAppender;
649

650
                    /**
651
                     * The represented method's minimum visibility.
652
                     */
653
                    private final Visibility visibility;
654

655
                    /**
656
                     * Creates a new record for an implemented method without attributes or a modifier resolver.
657
                     *
658
                     * @param methodDescription The implemented method.
659
                     * @param byteCodeAppender  The byte code appender to apply.
660
                     */
661
                    public WithBody(MethodDescription methodDescription, ByteCodeAppender byteCodeAppender) {
662
                        this(methodDescription, byteCodeAppender, MethodAttributeAppender.NoOp.INSTANCE, methodDescription.getVisibility());
1✔
663
                    }
1✔
664

665
                    /**
666
                     * Creates a new entry for a method that defines a method as byte code.
667
                     *
668
                     * @param methodDescription       The implemented method.
669
                     * @param byteCodeAppender        The byte code appender to apply.
670
                     * @param methodAttributeAppender The method attribute appender to apply.
671
                     * @param visibility              The represented method's minimum visibility.
672
                     */
673
                    public WithBody(MethodDescription methodDescription,
674
                                    ByteCodeAppender byteCodeAppender,
675
                                    MethodAttributeAppender methodAttributeAppender,
676
                                    Visibility visibility) {
1✔
677
                        this.methodDescription = methodDescription;
1✔
678
                        this.byteCodeAppender = byteCodeAppender;
1✔
679
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
680
                        this.visibility = visibility;
1✔
681
                    }
1✔
682

683
                    /**
684
                     * {@inheritDoc}
685
                     */
686
                    public MethodDescription getMethod() {
687
                        return methodDescription;
1✔
688
                    }
689

690
                    /**
691
                     * {@inheritDoc}
692
                     */
693
                    public Sort getSort() {
694
                        return Sort.IMPLEMENTED;
1✔
695
                    }
696

697
                    /**
698
                     * {@inheritDoc}
699
                     */
700
                    public Visibility getVisibility() {
701
                        return visibility;
1✔
702
                    }
703

704
                    /**
705
                     * {@inheritDoc}
706
                     */
707
                    public void applyHead(MethodVisitor methodVisitor) {
708
                        /* do nothing */
709
                    }
1✔
710

711
                    /**
712
                     * {@inheritDoc}
713
                     */
714
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
715
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
716
                        methodVisitor.visitCode();
1✔
717
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
718
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
719
                    }
1✔
720

721
                    /**
722
                     * {@inheritDoc}
723
                     */
724
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
725
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
726
                    }
1✔
727

728
                    /**
729
                     * {@inheritDoc}
730
                     */
731
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
732
                        return byteCodeAppender.apply(methodVisitor, implementationContext, methodDescription);
1✔
733
                    }
734

735
                    /**
736
                     * {@inheritDoc}
737
                     */
738
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
739
                        return new WithBody(methodDescription,
1✔
740
                                new ByteCodeAppender.Compound(byteCodeAppender, this.byteCodeAppender),
741
                                methodAttributeAppender,
742
                                visibility);
743
                    }
744
                }
745

746
                /**
747
                 * Describes an entry that defines a method but without byte code and without an annotation value.
748
                 */
749
                @HashCodeAndEqualsPlugin.Enhance
750
                public static class WithoutBody extends ForDefinedMethod {
751

752
                    /**
753
                     * The implemented method.
754
                     */
755
                    private final MethodDescription methodDescription;
756

757
                    /**
758
                     * The method attribute appender to apply.
759
                     */
760
                    private final MethodAttributeAppender methodAttributeAppender;
761

762
                    /**
763
                     * The represented method's minimum visibility.
764
                     */
765
                    private final Visibility visibility;
766

767
                    /**
768
                     * Creates a new entry for a method that is defines but does not append byte code, i.e. is native or abstract.
769
                     *
770
                     * @param methodDescription       The implemented method.
771
                     * @param methodAttributeAppender The method attribute appender to apply.
772
                     * @param visibility              The represented method's minimum visibility.
773
                     */
774
                    public WithoutBody(MethodDescription methodDescription, MethodAttributeAppender methodAttributeAppender, Visibility visibility) {
1✔
775
                        this.methodDescription = methodDescription;
1✔
776
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
777
                        this.visibility = visibility;
1✔
778
                    }
1✔
779

780
                    /**
781
                     * {@inheritDoc}
782
                     */
783
                    public MethodDescription getMethod() {
784
                        return methodDescription;
1✔
785
                    }
786

787
                    /**
788
                     * {@inheritDoc}
789
                     */
790
                    public Sort getSort() {
791
                        return Sort.DEFINED;
1✔
792
                    }
793

794
                    /**
795
                     * {@inheritDoc}
796
                     */
797
                    public Visibility getVisibility() {
798
                        return visibility;
1✔
799
                    }
800

801
                    /**
802
                     * {@inheritDoc}
803
                     */
804
                    public void applyHead(MethodVisitor methodVisitor) {
805
                        /* do nothing */
806
                    }
1✔
807

808
                    /**
809
                     * {@inheritDoc}
810
                     */
811
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
812
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
813
                    }
1✔
814

815
                    /**
816
                     * {@inheritDoc}
817
                     */
818
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
819
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
820
                    }
1✔
821

822
                    /**
823
                     * {@inheritDoc}
824
                     */
825
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
826
                        throw new IllegalStateException("Cannot apply code for abstract method on " + methodDescription);
1✔
827
                    }
828

829
                    /**
830
                     * {@inheritDoc}
831
                     */
832
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
833
                        throw new IllegalStateException("Cannot prepend code for abstract method on " + methodDescription);
1✔
834
                    }
835
                }
836

837
                /**
838
                 * Describes an entry that defines a method with a default annotation value.
839
                 */
840
                @HashCodeAndEqualsPlugin.Enhance
841
                public static class WithAnnotationDefaultValue extends ForDefinedMethod {
842

843
                    /**
844
                     * The implemented method.
845
                     */
846
                    private final MethodDescription methodDescription;
847

848
                    /**
849
                     * The annotation value to define.
850
                     */
851
                    private final AnnotationValue<?, ?> annotationValue;
852

853
                    /**
854
                     * The method attribute appender to apply.
855
                     */
856
                    private final MethodAttributeAppender methodAttributeAppender;
857

858
                    /**
859
                     * Creates a new entry for defining a method with a default annotation value.
860
                     *
861
                     * @param methodDescription       The implemented method.
862
                     * @param annotationValue         The annotation value to define.
863
                     * @param methodAttributeAppender The method attribute appender to apply.
864
                     */
865
                    public WithAnnotationDefaultValue(MethodDescription methodDescription,
866
                                                      AnnotationValue<?, ?> annotationValue,
867
                                                      MethodAttributeAppender methodAttributeAppender) {
1✔
868
                        this.methodDescription = methodDescription;
1✔
869
                        this.annotationValue = annotationValue;
1✔
870
                        this.methodAttributeAppender = methodAttributeAppender;
1✔
871
                    }
1✔
872

873
                    /**
874
                     * {@inheritDoc}
875
                     */
876
                    public MethodDescription getMethod() {
877
                        return methodDescription;
1✔
878
                    }
879

880
                    /**
881
                     * {@inheritDoc}
882
                     */
883
                    public Sort getSort() {
884
                        return Sort.DEFINED;
1✔
885
                    }
886

887
                    /**
888
                     * {@inheritDoc}
889
                     */
890
                    public Visibility getVisibility() {
891
                        return methodDescription.getVisibility();
1✔
892
                    }
893

894
                    /**
895
                     * {@inheritDoc}
896
                     */
897
                    public void applyHead(MethodVisitor methodVisitor) {
898
                        if (!methodDescription.isDefaultValue(annotationValue)) {
1✔
899
                            throw new IllegalStateException("Cannot set " + annotationValue + " as default for " + methodDescription);
1✔
900
                        }
901
                        AnnotationVisitor annotationVisitor = methodVisitor.visitAnnotationDefault();
1✔
902
                        AnnotationAppender.Default.apply(annotationVisitor,
1✔
903
                                methodDescription.getReturnType().asErasure(),
1✔
904
                                AnnotationAppender.NO_NAME,
905
                                annotationValue.resolve());
1✔
906
                        annotationVisitor.visitEnd();
1✔
907
                    }
1✔
908

909
                    /**
910
                     * {@inheritDoc}
911
                     */
912
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
913
                        methodAttributeAppender.apply(methodVisitor, methodDescription, annotationValueFilterFactory.on(methodDescription));
1✔
914
                    }
1✔
915

916
                    /**
917
                     * {@inheritDoc}
918
                     */
919
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
920
                        throw new IllegalStateException("Cannot apply attributes for default value on " + methodDescription);
1✔
921
                    }
922

923
                    /**
924
                     * {@inheritDoc}
925
                     */
926
                    public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
927
                        throw new IllegalStateException("Cannot apply code for default value on " + methodDescription);
1✔
928
                    }
929

930
                    /**
931
                     * {@inheritDoc}
932
                     */
933
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
934
                        throw new IllegalStateException("Cannot prepend code for default value on " + methodDescription);
1✔
935
                    }
936
                }
937

938
                /**
939
                 * A record for a visibility bridge.
940
                 */
941
                @HashCodeAndEqualsPlugin.Enhance
942
                public static class OfVisibilityBridge extends ForDefinedMethod implements ByteCodeAppender {
943

944
                    /**
945
                     * The visibility bridge.
946
                     */
947
                    private final MethodDescription visibilityBridge;
948

949
                    /**
950
                     * The method the visibility bridge invokes.
951
                     */
952
                    private final MethodDescription bridgeTarget;
953

954
                    /**
955
                     * The type on which the bridge method is invoked.
956
                     */
957
                    private final TypeDescription bridgeType;
958

959
                    /**
960
                     * The attribute appender to apply to the visibility bridge.
961
                     */
962
                    private final MethodAttributeAppender attributeAppender;
963

964
                    /**
965
                     * Creates a new record for a visibility bridge.
966
                     *
967
                     * @param visibilityBridge  The visibility bridge.
968
                     * @param bridgeTarget      The method the visibility bridge invokes.
969
                     * @param bridgeType        The type of the instrumented type.
970
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
971
                     */
972
                    protected OfVisibilityBridge(MethodDescription visibilityBridge,
973
                                                 MethodDescription bridgeTarget,
974
                                                 TypeDescription bridgeType,
975
                                                 MethodAttributeAppender attributeAppender) {
1✔
976
                        this.visibilityBridge = visibilityBridge;
1✔
977
                        this.bridgeTarget = bridgeTarget;
1✔
978
                        this.bridgeType = bridgeType;
1✔
979
                        this.attributeAppender = attributeAppender;
1✔
980
                    }
1✔
981

982
                    /**
983
                     * Creates a record for a visibility bridge.
984
                     *
985
                     * @param instrumentedType  The instrumented type.
986
                     * @param bridgeTarget      The target method of the visibility bridge.
987
                     * @param attributeAppender The attribute appender to apply to the visibility bridge.
988
                     * @return A record describing the visibility bridge.
989
                     */
990
                    public static Record of(TypeDescription instrumentedType, MethodDescription bridgeTarget, MethodAttributeAppender attributeAppender) {
991
                        // Default method bridges must be dispatched on an implemented interface type, not considering the declaring type.
992
                        TypeDefinition bridgeType = null;
1✔
993
                        if (bridgeTarget.isDefaultMethod()) {
1✔
994
                            TypeDescription declaringType = bridgeTarget.getDeclaringType().asErasure();
1✔
995
                            for (TypeDescription interfaceType : instrumentedType.getInterfaces().asErasures().filter(isSubTypeOf(declaringType))) {
1✔
996
                                if (bridgeType == null || declaringType.isAssignableTo(bridgeType.asErasure())) {
1✔
997
                                    bridgeType = interfaceType;
1✔
998
                                }
999
                            }
1✔
1000
                        }
1001
                        // Non-default method or default method that is inherited by a super class.
1002
                        if (bridgeType == null) {
1✔
1003
                            bridgeType = instrumentedType.getSuperClass();
1✔
1004
                            if (bridgeType == null) {
1✔
1005
                                bridgeType = TypeDescription.ForLoadedType.of(Object.class);
×
1006
                            }
1007
                        }
1008
                        return new OfVisibilityBridge(new VisibilityBridge(instrumentedType, bridgeTarget),
1✔
1009
                                bridgeTarget,
1010
                                bridgeType.asErasure(),
1✔
1011
                                attributeAppender);
1012
                    }
1013

1014
                    /**
1015
                     * {@inheritDoc}
1016
                     */
1017
                    public MethodDescription getMethod() {
1018
                        return visibilityBridge;
1✔
1019
                    }
1020

1021
                    /**
1022
                     * {@inheritDoc}
1023
                     */
1024
                    public Sort getSort() {
1025
                        return Sort.IMPLEMENTED;
1✔
1026
                    }
1027

1028
                    /**
1029
                     * {@inheritDoc}
1030
                     */
1031
                    public Visibility getVisibility() {
1032
                        return bridgeTarget.getVisibility();
1✔
1033
                    }
1034

1035
                    /**
1036
                     * {@inheritDoc}
1037
                     */
1038
                    public Record prepend(ByteCodeAppender byteCodeAppender) {
1039
                        return new ForDefinedMethod.WithBody(visibilityBridge,
1✔
1040
                                new ByteCodeAppender.Compound(this, byteCodeAppender),
1041
                                attributeAppender,
1042
                                bridgeTarget.getVisibility());
1✔
1043
                    }
1044

1045
                    /**
1046
                     * {@inheritDoc}
1047
                     */
1048
                    public void applyHead(MethodVisitor methodVisitor) {
1049
                        /* do nothing */
1050
                    }
1✔
1051

1052
                    /**
1053
                     * {@inheritDoc}
1054
                     */
1055
                    public void applyBody(MethodVisitor methodVisitor, Implementation.Context implementationContext, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1056
                        applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1057
                        methodVisitor.visitCode();
1✔
1058
                        ByteCodeAppender.Size size = applyCode(methodVisitor, implementationContext);
1✔
1059
                        methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1060
                    }
1✔
1061

1062
                    /**
1063
                     * {@inheritDoc}
1064
                     */
1065
                    public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1066
                        attributeAppender.apply(methodVisitor, visibilityBridge, annotationValueFilterFactory.on(visibilityBridge));
1✔
1067
                    }
1✔
1068

1069
                    /**
1070
                     * {@inheritDoc}
1071
                     */
1072
                    public Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1073
                        return apply(methodVisitor, implementationContext, visibilityBridge);
1✔
1074
                    }
1075

1076
                    /**
1077
                     * {@inheritDoc}
1078
                     */
1079
                    public Size apply(MethodVisitor methodVisitor, Implementation.Context implementationContext, MethodDescription instrumentedMethod) {
1080
                        return new ByteCodeAppender.Simple(
1✔
1081
                                MethodVariableAccess.allArgumentsOf(instrumentedMethod).prependThisReference(),
1✔
1082
                                MethodInvocation.invoke(bridgeTarget).special(bridgeType),
1✔
1083
                                MethodReturn.of(instrumentedMethod.getReturnType())
1✔
1084
                        ).apply(methodVisitor, implementationContext, instrumentedMethod);
1✔
1085
                    }
1086

1087
                    /**
1088
                     * A method describing a visibility bridge.
1089
                     */
1090
                    protected static class VisibilityBridge extends MethodDescription.InDefinedShape.AbstractBase {
1091

1092
                        /**
1093
                         * The instrumented type.
1094
                         */
1095
                        private final TypeDescription instrumentedType;
1096

1097
                        /**
1098
                         * The method that is the target of the bridge.
1099
                         */
1100
                        private final MethodDescription bridgeTarget;
1101

1102
                        /**
1103
                         * Creates a new visibility bridge.
1104
                         *
1105
                         * @param instrumentedType The instrumented type.
1106
                         * @param bridgeTarget     The method that is the target of the bridge.
1107
                         */
1108
                        protected VisibilityBridge(TypeDescription instrumentedType, MethodDescription bridgeTarget) {
1✔
1109
                            this.instrumentedType = instrumentedType;
1✔
1110
                            this.bridgeTarget = bridgeTarget;
1✔
1111
                        }
1✔
1112

1113
                        /**
1114
                         * {@inheritDoc}
1115
                         */
1116
                        @Nonnull
1117
                        public TypeDescription getDeclaringType() {
1118
                            return instrumentedType;
1✔
1119
                        }
1120

1121
                        /**
1122
                         * {@inheritDoc}
1123
                         */
1124
                        public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1125
                            return new ParameterList.Explicit.ForTypes(this, bridgeTarget.getParameters().asTypeList().asRawTypes());
1✔
1126
                        }
1127

1128
                        /**
1129
                         * {@inheritDoc}
1130
                         */
1131
                        public TypeDescription.Generic getReturnType() {
1132
                            return bridgeTarget.getReturnType().asRawType();
1✔
1133
                        }
1134

1135
                        /**
1136
                         * {@inheritDoc}
1137
                         */
1138
                        public TypeList.Generic getExceptionTypes() {
1139
                            return bridgeTarget.getExceptionTypes().asRawTypes();
1✔
1140
                        }
1141

1142
                        /**
1143
                         * {@inheritDoc}
1144
                         */
1145
                        @MaybeNull
1146
                        public AnnotationValue<?, ?> getDefaultValue() {
1147
                            return AnnotationValue.UNDEFINED;
×
1148
                        }
1149

1150
                        /**
1151
                         * {@inheritDoc}
1152
                         */
1153
                        public TypeList.Generic getTypeVariables() {
1154
                            return new TypeList.Generic.Empty();
1✔
1155
                        }
1156

1157
                        /**
1158
                         * {@inheritDoc}
1159
                         */
1160
                        public AnnotationList getDeclaredAnnotations() {
1161
                            return bridgeTarget.getDeclaredAnnotations();
1✔
1162
                        }
1163

1164
                        /**
1165
                         * {@inheritDoc}
1166
                         */
1167
                        public int getModifiers() {
1168
                            return (bridgeTarget.getModifiers() | Opcodes.ACC_SYNTHETIC | Opcodes.ACC_BRIDGE) & ~Opcodes.ACC_NATIVE;
1✔
1169
                        }
1170

1171
                        /**
1172
                         * {@inheritDoc}
1173
                         */
1174
                        public String getInternalName() {
1175
                            return bridgeTarget.getName();
1✔
1176
                        }
1177
                    }
1178
                }
1179
            }
1180

1181
            /**
1182
             * A wrapper that appends accessor bridges for a method's implementation. The bridges are only added if
1183
             * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool.Record#apply(ClassVisitor, Implementation.Context, AnnotationValueFilter.Factory)}
1184
             * is invoked such that bridges are not appended for methods that are rebased or redefined as such types already have bridge methods in place.
1185
             */
1186
            @HashCodeAndEqualsPlugin.Enhance
1187
            class AccessBridgeWrapper implements Record {
1188

1189
                /**
1190
                 * The delegate for implementing the bridge's target.
1191
                 */
1192
                private final Record delegate;
1193

1194
                /**
1195
                 * The instrumented type that defines the bridge methods and the bridge target.
1196
                 */
1197
                private final TypeDescription instrumentedType;
1198

1199
                /**
1200
                 * The target of the bridge method.
1201
                 */
1202
                private final MethodDescription bridgeTarget;
1203

1204
                /**
1205
                 * A collection of all tokens representing all bridge methods.
1206
                 */
1207
                private final Set<MethodDescription.TypeToken> bridgeTypes;
1208

1209
                /**
1210
                 * The attribute appender being applied for the bridge target.
1211
                 */
1212
                private final MethodAttributeAppender attributeAppender;
1213

1214
                /**
1215
                 * Creates a wrapper for adding accessor bridges.
1216
                 *
1217
                 * @param delegate          The delegate for implementing the bridge's target.
1218
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1219
                 * @param bridgeTarget      The target of the bridge method.
1220
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1221
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1222
                 */
1223
                protected AccessBridgeWrapper(Record delegate,
1224
                                              TypeDescription instrumentedType,
1225
                                              MethodDescription bridgeTarget,
1226
                                              Set<MethodDescription.TypeToken> bridgeTypes,
1227
                                              MethodAttributeAppender attributeAppender) {
1✔
1228
                    this.delegate = delegate;
1✔
1229
                    this.instrumentedType = instrumentedType;
1✔
1230
                    this.bridgeTarget = bridgeTarget;
1✔
1231
                    this.bridgeTypes = bridgeTypes;
1✔
1232
                    this.attributeAppender = attributeAppender;
1✔
1233
                }
1✔
1234

1235
                /**
1236
                 * Wraps the given record in an accessor bridge wrapper if necessary.
1237
                 *
1238
                 * @param delegate          The delegate for implementing the bridge's target.
1239
                 * @param instrumentedType  The instrumented type that defines the bridge methods and the bridge target.
1240
                 * @param bridgeTarget      The bridge methods' target methods.
1241
                 * @param bridgeTypes       A collection of all tokens representing all bridge methods.
1242
                 * @param attributeAppender The attribute appender being applied for the bridge target.
1243
                 * @return The given record wrapped by a bridge method wrapper if necessary.
1244
                 */
1245
                public static Record of(Record delegate,
1246
                                        TypeDescription instrumentedType,
1247
                                        MethodDescription bridgeTarget,
1248
                                        Set<MethodDescription.TypeToken> bridgeTypes,
1249
                                        MethodAttributeAppender attributeAppender) {
1250
                    Set<MethodDescription.TypeToken> compatibleBridgeTypes = new HashSet<MethodDescription.TypeToken>();
1✔
1251
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1252
                        if (bridgeTarget.isBridgeCompatible(bridgeType)) {
1✔
1253
                            compatibleBridgeTypes.add(bridgeType);
1✔
1254
                        }
1255
                    }
1✔
1256
                    return compatibleBridgeTypes.isEmpty() || (instrumentedType.isInterface() && !delegate.getSort().isImplemented())
1✔
1257
                            ? delegate
1258
                            : new AccessBridgeWrapper(delegate, instrumentedType, bridgeTarget, compatibleBridgeTypes, attributeAppender);
1259
                }
1260

1261
                /**
1262
                 * {@inheritDoc}
1263
                 */
1264
                public Sort getSort() {
1265
                    return delegate.getSort();
1✔
1266
                }
1267

1268
                /**
1269
                 * {@inheritDoc}
1270
                 */
1271
                public MethodDescription getMethod() {
1272
                    return bridgeTarget;
×
1273
                }
1274

1275
                /**
1276
                 * {@inheritDoc}
1277
                 */
1278
                public Visibility getVisibility() {
1279
                    return delegate.getVisibility();
1✔
1280
                }
1281

1282
                /**
1283
                 * {@inheritDoc}
1284
                 */
1285
                public Record prepend(ByteCodeAppender byteCodeAppender) {
1286
                    return new AccessBridgeWrapper(delegate.prepend(byteCodeAppender), instrumentedType, bridgeTarget, bridgeTypes, attributeAppender);
1✔
1287
                }
1288

1289
                /**
1290
                 * {@inheritDoc}
1291
                 */
1292
                public void apply(ClassVisitor classVisitor,
1293
                                  Implementation.Context implementationContext,
1294
                                  AnnotationValueFilter.Factory annotationValueFilterFactory) {
1295
                    delegate.apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
1296
                    for (MethodDescription.TypeToken bridgeType : bridgeTypes) {
1✔
1297
                        MethodDescription.InDefinedShape bridgeMethod = new AccessorBridge(bridgeTarget, bridgeType, instrumentedType);
1✔
1298
                        MethodDescription.InDefinedShape bridgeTarget = new BridgeTarget(this.bridgeTarget, instrumentedType);
1✔
1299
                        MethodVisitor methodVisitor = classVisitor.visitMethod(bridgeMethod.getActualModifiers(true, getVisibility()),
1✔
1300
                                bridgeMethod.getInternalName(),
1✔
1301
                                bridgeMethod.getDescriptor(),
1✔
1302
                                MethodDescription.NON_GENERIC_SIGNATURE,
1303
                                bridgeMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
1304
                        if (methodVisitor != null) {
1✔
1305
                            attributeAppender.apply(methodVisitor, bridgeMethod, annotationValueFilterFactory.on(instrumentedType));
1✔
1306
                            methodVisitor.visitCode();
1✔
1307
                            ByteCodeAppender.Size size = new ByteCodeAppender.Simple(
1✔
1308
                                    MethodVariableAccess.allArgumentsOf(bridgeMethod).asBridgeOf(bridgeTarget).prependThisReference(),
1✔
1309
                                    MethodInvocation.invoke(bridgeTarget).virtual(instrumentedType),
1✔
1310
                                    bridgeTarget.getReturnType().asErasure().isAssignableTo(bridgeMethod.getReturnType().asErasure())
1✔
1311
                                            ? StackManipulation.Trivial.INSTANCE
1312
                                            : TypeCasting.to(bridgeMethod.getReturnType().asErasure()),
1✔
1313
                                    MethodReturn.of(bridgeMethod.getReturnType())
1✔
1314
                            ).apply(methodVisitor, implementationContext, bridgeMethod);
1✔
1315
                            methodVisitor.visitMaxs(size.getOperandStackSize(), size.getLocalVariableSize());
1✔
1316
                            methodVisitor.visitEnd();
1✔
1317
                        }
1318
                    }
1✔
1319
                }
1✔
1320

1321
                /**
1322
                 * {@inheritDoc}
1323
                 */
1324
                public void applyHead(MethodVisitor methodVisitor) {
1325
                    delegate.applyHead(methodVisitor);
1✔
1326
                }
1✔
1327

1328
                /**
1329
                 * {@inheritDoc}
1330
                 */
1331
                public void applyBody(MethodVisitor methodVisitor,
1332
                                      Implementation.Context implementationContext,
1333
                                      AnnotationValueFilter.Factory annotationValueFilterFactory) {
1334
                    delegate.applyBody(methodVisitor, implementationContext, annotationValueFilterFactory);
1✔
1335
                }
1✔
1336

1337
                /**
1338
                 * {@inheritDoc}
1339
                 */
1340
                public void applyAttributes(MethodVisitor methodVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1341
                    delegate.applyAttributes(methodVisitor, annotationValueFilterFactory);
1✔
1342
                }
1✔
1343

1344
                /**
1345
                 * {@inheritDoc}
1346
                 */
1347
                public ByteCodeAppender.Size applyCode(MethodVisitor methodVisitor, Implementation.Context implementationContext) {
1348
                    return delegate.applyCode(methodVisitor, implementationContext);
1✔
1349
                }
1350

1351
                /**
1352
                 * A method representing an accessor bridge method.
1353
                 */
1354
                protected static class AccessorBridge extends MethodDescription.InDefinedShape.AbstractBase {
1355

1356
                    /**
1357
                     * The target method of the bridge.
1358
                     */
1359
                    private final MethodDescription bridgeTarget;
1360

1361
                    /**
1362
                     * The bridge's type token.
1363
                     */
1364
                    private final MethodDescription.TypeToken bridgeType;
1365

1366
                    /**
1367
                     * The instrumented type defining the bridge target.
1368
                     */
1369
                    private final TypeDescription instrumentedType;
1370

1371
                    /**
1372
                     * Creates a new accessor bridge method.
1373
                     *
1374
                     * @param bridgeTarget     The target method of the bridge.
1375
                     * @param bridgeType       The bridge's type token.
1376
                     * @param instrumentedType The instrumented type defining the bridge target.
1377
                     */
1378
                    protected AccessorBridge(MethodDescription bridgeTarget, TypeToken bridgeType, TypeDescription instrumentedType) {
1✔
1379
                        this.bridgeTarget = bridgeTarget;
1✔
1380
                        this.bridgeType = bridgeType;
1✔
1381
                        this.instrumentedType = instrumentedType;
1✔
1382
                    }
1✔
1383

1384
                    /**
1385
                     * {@inheritDoc}
1386
                     */
1387
                    @Nonnull
1388
                    public TypeDescription getDeclaringType() {
1389
                        return instrumentedType;
1✔
1390
                    }
1391

1392
                    /**
1393
                     * {@inheritDoc}
1394
                     */
1395
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1396
                        return new ParameterList.Explicit.ForTypes(this, bridgeType.getParameterTypes());
1✔
1397
                    }
1398

1399
                    /**
1400
                     * {@inheritDoc}
1401
                     */
1402
                    public TypeDescription.Generic getReturnType() {
1403
                        return bridgeType.getReturnType().asGenericType();
1✔
1404
                    }
1405

1406
                    /**
1407
                     * {@inheritDoc}
1408
                     */
1409
                    public TypeList.Generic getExceptionTypes() {
1410
                        return bridgeTarget.getExceptionTypes().accept(TypeDescription.Generic.Visitor.TypeErasing.INSTANCE);
1✔
1411
                    }
1412

1413
                    /**
1414
                     * {@inheritDoc}
1415
                     */
1416
                    @MaybeNull
1417
                    public AnnotationValue<?, ?> getDefaultValue() {
1418
                        return AnnotationValue.UNDEFINED;
×
1419
                    }
1420

1421
                    /**
1422
                     * {@inheritDoc}
1423
                     */
1424
                    public TypeList.Generic getTypeVariables() {
1425
                        return new TypeList.Generic.Empty();
1✔
1426
                    }
1427

1428
                    /**
1429
                     * {@inheritDoc}
1430
                     */
1431
                    public AnnotationList getDeclaredAnnotations() {
1432
                        return new AnnotationList.Empty();
1✔
1433
                    }
1434

1435
                    /**
1436
                     * {@inheritDoc}
1437
                     */
1438
                    public int getModifiers() {
1439
                        return (bridgeTarget.getModifiers() | Opcodes.ACC_BRIDGE | Opcodes.ACC_SYNTHETIC) & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE);
1✔
1440
                    }
1441

1442
                    /**
1443
                     * {@inheritDoc}
1444
                     */
1445
                    public String getInternalName() {
1446
                        return bridgeTarget.getInternalName();
1✔
1447
                    }
1448
                }
1449

1450
                /**
1451
                 * A method representing a bridge's target method in its defined shape.
1452
                 */
1453
                protected static class BridgeTarget extends MethodDescription.InDefinedShape.AbstractBase {
1454

1455
                    /**
1456
                     * The target method of the bridge.
1457
                     */
1458
                    private final MethodDescription bridgeTarget;
1459

1460
                    /**
1461
                     * The instrumented type defining the bridge target.
1462
                     */
1463
                    private final TypeDescription instrumentedType;
1464

1465
                    /**
1466
                     * Creates a new bridge target.
1467
                     *
1468
                     * @param bridgeTarget     The target method of the bridge.
1469
                     * @param instrumentedType The instrumented type defining the bridge target.
1470
                     */
1471
                    protected BridgeTarget(MethodDescription bridgeTarget, TypeDescription instrumentedType) {
1✔
1472
                        this.bridgeTarget = bridgeTarget;
1✔
1473
                        this.instrumentedType = instrumentedType;
1✔
1474
                    }
1✔
1475

1476
                    /**
1477
                     * {@inheritDoc}
1478
                     */
1479
                    @Nonnull
1480
                    public TypeDescription getDeclaringType() {
1481
                        return instrumentedType;
1✔
1482
                    }
1483

1484
                    /**
1485
                     * {@inheritDoc}
1486
                     */
1487
                    public ParameterList<ParameterDescription.InDefinedShape> getParameters() {
1488
                        return new ParameterList.ForTokens(this, bridgeTarget.getParameters().asTokenList(is(instrumentedType)));
1✔
1489
                    }
1490

1491
                    /**
1492
                     * {@inheritDoc}
1493
                     */
1494
                    public TypeDescription.Generic getReturnType() {
1495
                        return bridgeTarget.getReturnType();
1✔
1496
                    }
1497

1498
                    /**
1499
                     * {@inheritDoc}
1500
                     */
1501
                    public TypeList.Generic getExceptionTypes() {
1502
                        return bridgeTarget.getExceptionTypes();
×
1503
                    }
1504

1505
                    /**
1506
                     * {@inheritDoc}
1507
                     */
1508
                    @MaybeNull
1509
                    public AnnotationValue<?, ?> getDefaultValue() {
1510
                        return bridgeTarget.getDefaultValue();
×
1511
                    }
1512

1513
                    /**
1514
                     * {@inheritDoc}
1515
                     */
1516
                    public TypeList.Generic getTypeVariables() {
1517
                        return bridgeTarget.getTypeVariables();
×
1518
                    }
1519

1520
                    /**
1521
                     * {@inheritDoc}
1522
                     */
1523
                    public AnnotationList getDeclaredAnnotations() {
1524
                        return bridgeTarget.getDeclaredAnnotations();
×
1525
                    }
1526

1527
                    /**
1528
                     * {@inheritDoc}
1529
                     */
1530
                    public int getModifiers() {
1531
                        return bridgeTarget.getModifiers();
1✔
1532
                    }
1533

1534
                    /**
1535
                     * {@inheritDoc}
1536
                     */
1537
                    public String getInternalName() {
1538
                        return bridgeTarget.getInternalName();
1✔
1539
                    }
1540
                }
1541
            }
1542
        }
1543
    }
1544

1545
    /**
1546
     * An record component pool that allows a lookup for how to implement a record component.
1547
     */
1548
    interface RecordComponentPool {
1549

1550
        /**
1551
         * Looks up a handler entry for a given record component.
1552
         *
1553
         * @param recordComponentDescription The record component being processed.
1554
         * @return A handler entry for the given record component.
1555
         */
1556
        Record target(RecordComponentDescription recordComponentDescription);
1557

1558
        /**
1559
         * An entry of a record component pool that describes how a record component is implemented.
1560
         *
1561
         * @see RecordComponentPool
1562
         */
1563
        interface Record {
1564

1565
            /**
1566
             * Determines if this record is implicit, i.e is not defined by a {@link RecordComponentPool}.
1567
             *
1568
             * @return {@code true} if this record is implicit.
1569
             */
1570
            boolean isImplicit();
1571

1572
            /**
1573
             * Returns the record component that this record represents.
1574
             *
1575
             * @return The record component that this record represents.
1576
             */
1577
            RecordComponentDescription getRecordComponent();
1578

1579
            /**
1580
             * Returns the record component attribute appender for a given record component.
1581
             *
1582
             * @return The record component appender to be applied on the given field.
1583
             */
1584
            RecordComponentAttributeAppender getRecordComponentAppender();
1585

1586
            /**
1587
             * Writes this record to a given class visitor.
1588
             *
1589
             * @param classVisitor                 The class visitor to which this record is to be written to.
1590
             * @param annotationValueFilterFactory The annotation value filter factory to apply when writing annotations.
1591
             */
1592
            void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1593

1594
            /**
1595
             * Applies this record to a record component visitor. This is not possible for implicit records.
1596
             *
1597
             * @param recordComponentVisitor       The record component visitor onto which this record is to be applied.
1598
             * @param annotationValueFilterFactory The annotation value filter factory to use for annotations.
1599
             */
1600
            void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory);
1601

1602
            /**
1603
             * A record for a simple field without a default value where all of the record component's declared annotations are appended.
1604
             */
1605
            @HashCodeAndEqualsPlugin.Enhance
1606
            class ForImplicitRecordComponent implements Record {
1607

1608
                /**
1609
                 * The implemented record component.
1610
                 */
1611
                private final RecordComponentDescription recordComponentDescription;
1612

1613
                /**
1614
                 * Creates a new record for a simple record component.
1615
                 *
1616
                 * @param recordComponentDescription The described record component.
1617
                 */
1618
                public ForImplicitRecordComponent(RecordComponentDescription recordComponentDescription) {
1✔
1619
                    this.recordComponentDescription = recordComponentDescription;
1✔
1620
                }
1✔
1621

1622
                /**
1623
                 * {@inheritDoc}
1624
                 */
1625
                public boolean isImplicit() {
1626
                    return true;
1✔
1627
                }
1628

1629
                /**
1630
                 * {@inheritDoc}
1631
                 */
1632
                public RecordComponentDescription getRecordComponent() {
1633
                    return recordComponentDescription;
×
1634
                }
1635

1636
                /**
1637
                 * {@inheritDoc}
1638
                 */
1639
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1640
                    throw new IllegalStateException("An implicit field record does not expose a field appender: " + this);
×
1641
                }
1642

1643
                /**
1644
                 * {@inheritDoc}
1645
                 */
1646
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1647
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1648
                            recordComponentDescription.getDescriptor(),
1✔
1649
                            recordComponentDescription.getGenericSignature());
1✔
1650
                    if (recordComponentVisitor != null) {
1✔
1651
                        RecordComponentAttributeAppender.ForInstrumentedRecordComponent.INSTANCE.apply(recordComponentVisitor,
1✔
1652
                                recordComponentDescription,
1653
                                annotationValueFilterFactory.on(recordComponentDescription));
1✔
1654
                        recordComponentVisitor.visitEnd();
1✔
1655
                    }
1656
                }
1✔
1657

1658
                /**
1659
                 * {@inheritDoc}
1660
                 */
1661
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1662
                    throw new IllegalStateException("An implicit field record is not intended for partial application: " + this);
1✔
1663
                }
1664
            }
1665

1666
            /**
1667
             * A record for a rich record component with attributes.
1668
             */
1669
            @HashCodeAndEqualsPlugin.Enhance
1670
            class ForExplicitRecordComponent implements Record {
1671

1672
                /**
1673
                 * The attribute appender for the record component.
1674
                 */
1675
                private final RecordComponentAttributeAppender attributeAppender;
1676

1677
                /**
1678
                 * The implemented record component.
1679
                 */
1680
                private final RecordComponentDescription recordComponentDescription;
1681

1682
                /**
1683
                 * Creates a record for a rich record component.
1684
                 *
1685
                 * @param attributeAppender          The attribute appender for the record component.
1686
                 * @param recordComponentDescription The implemented record component.
1687
                 */
1688
                public ForExplicitRecordComponent(RecordComponentAttributeAppender attributeAppender, RecordComponentDescription recordComponentDescription) {
1✔
1689
                    this.attributeAppender = attributeAppender;
1✔
1690
                    this.recordComponentDescription = recordComponentDescription;
1✔
1691
                }
1✔
1692

1693
                /**
1694
                 * {@inheritDoc}
1695
                 */
1696
                public boolean isImplicit() {
1697
                    return false;
1✔
1698
                }
1699

1700
                /**
1701
                 * {@inheritDoc}
1702
                 */
1703
                public RecordComponentDescription getRecordComponent() {
1704
                    return recordComponentDescription;
×
1705
                }
1706

1707
                /**
1708
                 * {@inheritDoc}
1709
                 */
1710
                public RecordComponentAttributeAppender getRecordComponentAppender() {
1711
                    return attributeAppender;
1✔
1712
                }
1713

1714
                /**
1715
                 * {@inheritDoc}
1716
                 */
1717
                public void apply(ClassVisitor classVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1718
                    RecordComponentVisitor recordComponentVisitor = classVisitor.visitRecordComponent(recordComponentDescription.getActualName(),
1✔
1719
                            recordComponentDescription.getDescriptor(),
1✔
1720
                            recordComponentDescription.getGenericSignature());
1✔
1721
                    if (recordComponentVisitor != null) {
1✔
1722
                        attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1723
                        recordComponentVisitor.visitEnd();
1✔
1724
                    }
1725
                }
1✔
1726

1727
                /**
1728
                 * {@inheritDoc}
1729
                 */
1730
                public void apply(RecordComponentVisitor recordComponentVisitor, AnnotationValueFilter.Factory annotationValueFilterFactory) {
1731
                    attributeAppender.apply(recordComponentVisitor, recordComponentDescription, annotationValueFilterFactory.on(recordComponentDescription));
1✔
1732
                }
1✔
1733
            }
1734
        }
1735

1736
        /**
1737
         * A record component pool that does not allow any look ups.
1738
         */
1739
        enum Disabled implements RecordComponentPool {
1✔
1740

1741
            /**
1742
             * The singleton instance.
1743
             */
1744
            INSTANCE;
1✔
1745

1746
            /**
1747
             * {@inheritDoc}
1748
             */
1749
            public Record target(RecordComponentDescription recordComponentDescription) {
1750
                throw new IllegalStateException("Cannot look up record component from disabled pool");
1✔
1751
            }
1752
        }
1753
    }
1754

1755
    /**
1756
     * A default implementation of a {@link net.bytebuddy.dynamic.scaffold.TypeWriter}.
1757
     *
1758
     * @param <S> The best known loaded type for the dynamically created type.
1759
     */
1760
    @HashCodeAndEqualsPlugin.Enhance
1761
    abstract class Default<S> implements TypeWriter<S> {
1762

1763
        /**
1764
         * Indicates an empty reference in a class file which is expressed by {@code null}.
1765
         */
1766
        @AlwaysNull
1767
        private static final String NO_REFERENCE = null;
1✔
1768

1769
        /**
1770
         * A folder for dumping class files or {@code null} if no dump should be generated.
1771
         */
1772
        @MaybeNull
1773
        protected static final String DUMP_FOLDER;
1774

1775
        /*
1776
         * Reads the dumping property that is set at program start up. This might cause an error because of security constraints.
1777
         */
1778
        static {
1779
            String dumpFolder;
1780
            try {
1781
                dumpFolder = doPrivileged(new GetSystemPropertyAction(DUMP_PROPERTY));
1✔
1782
            } catch (RuntimeException exception) {
×
1783
                dumpFolder = null;
×
1784
            }
1✔
1785
            DUMP_FOLDER = dumpFolder;
1✔
1786
        }
1✔
1787

1788
        /**
1789
         * The instrumented type to be created.
1790
         */
1791
        protected final TypeDescription instrumentedType;
1792

1793
        /**
1794
         * The class file specified by the user.
1795
         */
1796
        protected final ClassFileVersion classFileVersion;
1797

1798
        /**
1799
         * The field pool to use.
1800
         */
1801
        protected final FieldPool fieldPool;
1802

1803
        /**
1804
         * The record component pool to use.
1805
         */
1806
        protected final RecordComponentPool recordComponentPool;
1807

1808
        /**
1809
         * The explicit auxiliary types to add to the created type.
1810
         */
1811
        protected final List<? extends DynamicType> auxiliaryTypes;
1812

1813
        /**
1814
         * The instrumented type's declared fields.
1815
         */
1816
        protected final FieldList<FieldDescription.InDefinedShape> fields;
1817

1818
        /**
1819
         * The instrumented type's methods that are declared or inherited.
1820
         */
1821
        protected final MethodList<?> methods;
1822

1823
        /**
1824
         * The instrumented methods relevant to this type creation.
1825
         */
1826
        protected final MethodList<?> instrumentedMethods;
1827

1828
        /**
1829
         * The instrumented type's record components.
1830
         */
1831
        protected final RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents;
1832

1833
        /**
1834
         * The loaded type initializer to apply onto the created type after loading.
1835
         */
1836
        protected final LoadedTypeInitializer loadedTypeInitializer;
1837

1838
        /**
1839
         * The type initializer to include in the created type's type initializer.
1840
         */
1841
        protected final TypeInitializer typeInitializer;
1842

1843
        /**
1844
         * The type attribute appender to apply onto the instrumented type.
1845
         */
1846
        protected final TypeAttributeAppender typeAttributeAppender;
1847

1848
        /**
1849
         * The ASM visitor wrapper to apply onto the class writer.
1850
         */
1851
        protected final AsmVisitorWrapper asmVisitorWrapper;
1852

1853
        /**
1854
         * The annotation value filter factory to apply.
1855
         */
1856
        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
1857

1858
        /**
1859
         * The annotation retention to apply.
1860
         */
1861
        protected final AnnotationRetention annotationRetention;
1862

1863
        /**
1864
         * The naming strategy for auxiliary types to apply.
1865
         */
1866
        protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
1867

1868
        /**
1869
         * The implementation context factory to apply.
1870
         */
1871
        protected final Implementation.Context.Factory implementationContextFactory;
1872

1873
        /**
1874
         * Determines if a type should be explicitly validated.
1875
         */
1876
        protected final TypeValidation typeValidation;
1877

1878
        /**
1879
         * The class reader factory to use.
1880
         */
1881
        protected final AsmClassReader.Factory classReaderFactory;
1882

1883
        /**
1884
         * The class writer factory to use.
1885
         */
1886
        protected final AsmClassWriter.Factory classWriterFactory;
1887

1888
        /**
1889
         * The type pool to use for computing stack map frames, if required.
1890
         */
1891
        protected final TypePool typePool;
1892

1893
        /**
1894
         * Creates a new default type writer.
1895
         *
1896
         * @param instrumentedType             The instrumented type to be created.
1897
         * @param classFileVersion             The class file specified by the user.
1898
         * @param fieldPool                    The field pool to use.
1899
         * @param recordComponentPool          The record component pool to use.
1900
         * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
1901
         * @param fields                       The instrumented type's declared fields.
1902
         * @param methods                      The instrumented type's declared and virtually inherited methods.
1903
         * @param instrumentedMethods          The instrumented methods relevant to this type creation.
1904
         * @param recordComponents             The instrumented type's record components.
1905
         * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
1906
         * @param typeInitializer              The type initializer to include in the created type's type initializer.
1907
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
1908
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
1909
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
1910
         * @param annotationRetention          The annotation retention to apply.
1911
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
1912
         * @param implementationContextFactory The implementation context factory to apply.
1913
         * @param typeValidation               Determines if a type should be explicitly validated.
1914
         * @param classReaderFactory           The class reader factory to use.
1915
         * @param classWriterFactory           The class writer factory to use.
1916
         * @param typePool                     The type pool to use for computing stack map frames, if required.
1917
         */
1918
        protected Default(TypeDescription instrumentedType,
1919
                          ClassFileVersion classFileVersion,
1920
                          FieldPool fieldPool,
1921
                          RecordComponentPool recordComponentPool,
1922
                          List<? extends DynamicType> auxiliaryTypes,
1923
                          FieldList<FieldDescription.InDefinedShape> fields,
1924
                          MethodList<?> methods,
1925
                          MethodList<?> instrumentedMethods,
1926
                          RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
1927
                          LoadedTypeInitializer loadedTypeInitializer,
1928
                          TypeInitializer typeInitializer,
1929
                          TypeAttributeAppender typeAttributeAppender,
1930
                          AsmVisitorWrapper asmVisitorWrapper,
1931
                          AnnotationValueFilter.Factory annotationValueFilterFactory,
1932
                          AnnotationRetention annotationRetention,
1933
                          AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
1934
                          Implementation.Context.Factory implementationContextFactory,
1935
                          TypeValidation typeValidation,
1936
                          AsmClassReader.Factory classReaderFactory,
1937
                          AsmClassWriter.Factory classWriterFactory,
1938
                          TypePool typePool) {
1✔
1939
            this.instrumentedType = instrumentedType;
1✔
1940
            this.classFileVersion = classFileVersion;
1✔
1941
            this.fieldPool = fieldPool;
1✔
1942
            this.recordComponentPool = recordComponentPool;
1✔
1943
            this.auxiliaryTypes = auxiliaryTypes;
1✔
1944
            this.fields = fields;
1✔
1945
            this.methods = methods;
1✔
1946
            this.instrumentedMethods = instrumentedMethods;
1✔
1947
            this.recordComponents = recordComponents;
1✔
1948
            this.loadedTypeInitializer = loadedTypeInitializer;
1✔
1949
            this.typeInitializer = typeInitializer;
1✔
1950
            this.typeAttributeAppender = typeAttributeAppender;
1✔
1951
            this.asmVisitorWrapper = asmVisitorWrapper;
1✔
1952
            this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
1953
            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
1954
            this.annotationRetention = annotationRetention;
1✔
1955
            this.implementationContextFactory = implementationContextFactory;
1✔
1956
            this.typeValidation = typeValidation;
1✔
1957
            this.classReaderFactory = classReaderFactory;
1✔
1958
            this.classWriterFactory = classWriterFactory;
1✔
1959
            this.typePool = typePool;
1✔
1960
        }
1✔
1961

1962
        /**
1963
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1964
         *
1965
         * @param action The action to execute from a privileged context.
1966
         * @param <T>    The type of the action's resolved value.
1967
         * @return The action's resolved value.
1968
         */
1969
        @AccessControllerPlugin.Enhance
1970
        private static <T> T doPrivileged(PrivilegedAction<T> action) {
1971
            return action.run();
×
1972
        }
1973

1974
        /**
1975
         * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
1976
         *
1977
         * @param action The action to execute from a privileged context.
1978
         * @param <T>    The type of the action's resolved value.
1979
         * @return The action's resolved value.
1980
         * @throws Exception If an exception occurs.
1981
         */
1982
        @AccessControllerPlugin.Enhance
1983
        private static <T> T doPrivileged(PrivilegedExceptionAction<T> action) throws Exception {
1984
            return action.run();
×
1985
        }
1986

1987
        /**
1988
         * Creates a type writer for creating a new type.
1989
         *
1990
         * @param methodRegistry               The compiled method registry to use.
1991
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
1992
         * @param fieldPool                    The field pool to use.
1993
         * @param recordComponentPool          The record component pool to use.
1994
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
1995
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
1996
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
1997
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
1998
         * @param annotationRetention          The annotation retention to apply.
1999
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2000
         * @param implementationContextFactory The implementation context factory to apply.
2001
         * @param typeValidation               Determines if a type should be explicitly validated.
2002
         * @param classReaderFactory           The class reader factory to use.
2003
         * @param classWriterFactory           The class writer factory to use.
2004
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2005
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2006
         * @return A suitable type writer.
2007
         */
2008
        public static <U> TypeWriter<U> forCreation(MethodRegistry.Compiled methodRegistry,
2009
                                                    List<? extends DynamicType> auxiliaryTypes,
2010
                                                    FieldPool fieldPool,
2011
                                                    RecordComponentPool recordComponentPool,
2012
                                                    TypeAttributeAppender typeAttributeAppender,
2013
                                                    AsmVisitorWrapper asmVisitorWrapper,
2014
                                                    ClassFileVersion classFileVersion,
2015
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2016
                                                    AnnotationRetention annotationRetention,
2017
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2018
                                                    Implementation.Context.Factory implementationContextFactory,
2019
                                                    TypeValidation typeValidation,
2020
                                                    AsmClassReader.Factory classReaderFactory,
2021
                                                    AsmClassWriter.Factory classWriterFactory,
2022
                                                    TypePool typePool) {
2023
            return new ForCreation<U>(methodRegistry.getInstrumentedType(),
1✔
2024
                    classFileVersion,
2025
                    fieldPool,
2026
                    methodRegistry,
2027
                    recordComponentPool,
2028
                    auxiliaryTypes,
2029
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2030
                    methodRegistry.getMethods(),
1✔
2031
                    methodRegistry.getInstrumentedMethods(),
1✔
2032
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2033
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2034
                    methodRegistry.getTypeInitializer(),
1✔
2035
                    typeAttributeAppender,
2036
                    asmVisitorWrapper,
2037
                    annotationValueFilterFactory,
2038
                    annotationRetention,
2039
                    auxiliaryTypeNamingStrategy,
2040
                    implementationContextFactory,
2041
                    typeValidation,
2042
                    classReaderFactory,
2043
                    classWriterFactory,
2044
                    typePool);
2045
        }
2046

2047
        /**
2048
         * Creates a type writer for redefining a type.
2049
         *
2050
         * @param methodRegistry               The compiled method registry to use.
2051
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2052
         * @param fieldPool                    The field pool to use.
2053
         * @param recordComponentPool          The record component pool to use.
2054
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2055
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2056
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2057
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2058
         * @param annotationRetention          The annotation retention to apply.
2059
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2060
         * @param implementationContextFactory The implementation context factory to apply.
2061
         * @param typeValidation               Determines if a type should be explicitly validated.
2062
         * @param classReaderFactory           The class reader factory to use.
2063
         * @param classWriterFactory           The class writer factory to use.
2064
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2065
         * @param originalType                 The original type that is being redefined or rebased.
2066
         * @param classFileLocator             The class file locator for locating the original type's class file.
2067
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2068
         * @return A suitable type writer.
2069
         */
2070
        public static <U> TypeWriter<U> forRedefinition(MethodRegistry.Prepared methodRegistry,
2071
                                                        List<? extends DynamicType> auxiliaryTypes,
2072
                                                        FieldPool fieldPool,
2073
                                                        RecordComponentPool recordComponentPool,
2074
                                                        TypeAttributeAppender typeAttributeAppender,
2075
                                                        AsmVisitorWrapper asmVisitorWrapper,
2076
                                                        ClassFileVersion classFileVersion,
2077
                                                        AnnotationValueFilter.Factory annotationValueFilterFactory,
2078
                                                        AnnotationRetention annotationRetention,
2079
                                                        AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2080
                                                        Implementation.Context.Factory implementationContextFactory,
2081
                                                        TypeValidation typeValidation,
2082
                                                        AsmClassReader.Factory classReaderFactory,
2083
                                                        AsmClassWriter.Factory classWriterFactory,
2084
                                                        TypePool typePool,
2085
                                                        TypeDescription originalType,
2086
                                                        ClassFileLocator classFileLocator) {
2087
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2088
                    classFileVersion,
2089
                    fieldPool,
2090
                    recordComponentPool,
2091
                    auxiliaryTypes,
2092
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2093
                    methodRegistry.getMethods(),
1✔
2094
                    methodRegistry.getInstrumentedMethods(),
1✔
2095
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2096
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2097
                    methodRegistry.getTypeInitializer(),
1✔
2098
                    typeAttributeAppender,
2099
                    asmVisitorWrapper,
2100
                    annotationValueFilterFactory,
2101
                    annotationRetention,
2102
                    auxiliaryTypeNamingStrategy,
2103
                    implementationContextFactory,
2104
                    typeValidation,
2105
                    classReaderFactory,
2106
                    classWriterFactory,
2107
                    typePool,
2108
                    originalType,
2109
                    classFileLocator,
2110
                    methodRegistry,
2111
                    SubclassImplementationTarget.Factory.LEVEL_TYPE,
2112
                    MethodRebaseResolver.Disabled.INSTANCE);
2113
        }
2114

2115
        /**
2116
         * Creates a type writer for rebasing a type.
2117
         *
2118
         * @param methodRegistry               The compiled method registry to use.
2119
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2120
         * @param fieldPool                    The field pool to use.
2121
         * @param recordComponentPool          The record component pool to use.
2122
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2123
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2124
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2125
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2126
         * @param annotationRetention          The annotation retention to apply.
2127
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2128
         * @param implementationContextFactory The implementation context factory to apply.
2129
         * @param typeValidation               Determines if a type should be explicitly validated.
2130
         * @param classReaderFactory           The class reader factory to use.
2131
         * @param classWriterFactory           The class writer factory to use.
2132
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2133
         * @param originalType                 The original type that is being redefined or rebased.
2134
         * @param classFileLocator             The class file locator for locating the original type's class file.
2135
         * @param methodRebaseResolver         The method rebase resolver to use for rebasing names.
2136
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2137
         * @return A suitable type writer.
2138
         */
2139
        public static <U> TypeWriter<U> forRebasing(MethodRegistry.Prepared methodRegistry,
2140
                                                    List<? extends DynamicType> auxiliaryTypes,
2141
                                                    FieldPool fieldPool,
2142
                                                    RecordComponentPool recordComponentPool,
2143
                                                    TypeAttributeAppender typeAttributeAppender,
2144
                                                    AsmVisitorWrapper asmVisitorWrapper,
2145
                                                    ClassFileVersion classFileVersion,
2146
                                                    AnnotationValueFilter.Factory annotationValueFilterFactory,
2147
                                                    AnnotationRetention annotationRetention,
2148
                                                    AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2149
                                                    Implementation.Context.Factory implementationContextFactory,
2150
                                                    TypeValidation typeValidation,
2151
                                                    AsmClassReader.Factory classReaderFactory,
2152
                                                    AsmClassWriter.Factory classWriterFactory,
2153
                                                    TypePool typePool,
2154
                                                    TypeDescription originalType,
2155
                                                    ClassFileLocator classFileLocator,
2156
                                                    MethodRebaseResolver methodRebaseResolver) {
2157
            return new ForInlining.WithFullProcessing<U>(methodRegistry.getInstrumentedType(),
1✔
2158
                    classFileVersion,
2159
                    fieldPool,
2160
                    recordComponentPool,
2161
                    CompoundList.of(auxiliaryTypes, methodRebaseResolver.getAuxiliaryTypes()),
1✔
2162
                    methodRegistry.getInstrumentedType().getDeclaredFields(),
1✔
2163
                    methodRegistry.getMethods(),
1✔
2164
                    methodRegistry.getInstrumentedMethods(),
1✔
2165
                    methodRegistry.getInstrumentedType().getRecordComponents(),
1✔
2166
                    methodRegistry.getLoadedTypeInitializer(),
1✔
2167
                    methodRegistry.getTypeInitializer(),
1✔
2168
                    typeAttributeAppender,
2169
                    asmVisitorWrapper,
2170
                    annotationValueFilterFactory,
2171
                    annotationRetention,
2172
                    auxiliaryTypeNamingStrategy,
2173
                    implementationContextFactory,
2174
                    typeValidation,
2175
                    classReaderFactory,
2176
                    classWriterFactory,
2177
                    typePool,
2178
                    originalType,
2179
                    classFileLocator,
2180
                    methodRegistry,
2181
                    new RebaseImplementationTarget.Factory(methodRebaseResolver),
2182
                    methodRebaseResolver);
2183
        }
2184

2185
        /**
2186
         * Creates a type writer for decorating a type.
2187
         *
2188
         * @param instrumentedType             The instrumented type.
2189
         * @param classFileVersion             The class file version to use when no explicit class file version is applied.
2190
         * @param auxiliaryTypes               A list of explicitly required auxiliary types.
2191
         * @param methods                      The methods to instrument.
2192
         * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
2193
         * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
2194
         * @param annotationValueFilterFactory The annotation value filter factory to apply.
2195
         * @param annotationRetention          The annotation retention to apply.
2196
         * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
2197
         * @param implementationContextFactory The implementation context factory to apply.
2198
         * @param typeValidation               Determines if a type should be explicitly validated.
2199
         * @param classReaderFactory           The class reader factory to use.
2200
         * @param classWriterFactory           The class writer factory to use.
2201
         * @param typePool                     The type pool to use for computing stack map frames, if required.
2202
         * @param classFileLocator             The class file locator for locating the original type's class file.
2203
         * @param <U>                          A loaded type that the instrumented type guarantees to subclass.
2204
         * @return A suitable type writer.
2205
         */
2206
        public static <U> TypeWriter<U> forDecoration(TypeDescription instrumentedType,
2207
                                                      ClassFileVersion classFileVersion,
2208
                                                      List<? extends DynamicType> auxiliaryTypes,
2209
                                                      List<? extends MethodDescription> methods,
2210
                                                      TypeAttributeAppender typeAttributeAppender,
2211
                                                      AsmVisitorWrapper asmVisitorWrapper,
2212
                                                      AnnotationValueFilter.Factory annotationValueFilterFactory,
2213
                                                      AnnotationRetention annotationRetention,
2214
                                                      AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
2215
                                                      Implementation.Context.Factory implementationContextFactory,
2216
                                                      TypeValidation typeValidation,
2217
                                                      AsmClassReader.Factory classReaderFactory,
2218
                                                      AsmClassWriter.Factory classWriterFactory,
2219
                                                      TypePool typePool,
2220
                                                      ClassFileLocator classFileLocator) {
2221
            return new ForInlining.WithDecorationOnly<U>(instrumentedType,
1✔
2222
                    classFileVersion,
2223
                    auxiliaryTypes,
2224
                    new MethodList.Explicit<MethodDescription>(methods),
2225
                    typeAttributeAppender,
2226
                    asmVisitorWrapper,
2227
                    annotationValueFilterFactory,
2228
                    annotationRetention,
2229
                    auxiliaryTypeNamingStrategy,
2230
                    implementationContextFactory,
2231
                    typeValidation,
2232
                    classReaderFactory,
2233
                    classWriterFactory,
2234
                    typePool,
2235
                    classFileLocator);
2236
        }
2237

2238
        /**
2239
         * {@inheritDoc}
2240
         */
2241
        @SuppressFBWarnings(value = "REC_CATCH_EXCEPTION", justification = "Setting a debugging property should never change the program outcome.")
2242
        public DynamicType.Unloaded<S> make(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2243
            ClassDumpAction.Dispatcher dispatcher = DUMP_FOLDER == null
1✔
2244
                    ? ClassDumpAction.Dispatcher.Disabled.INSTANCE
2245
                    : new ClassDumpAction.Dispatcher.Enabled(DUMP_FOLDER, System.currentTimeMillis());
1✔
2246
            UnresolvedType unresolvedType = create(typeResolutionStrategy.injectedInto(typeInitializer), dispatcher);
1✔
2247
            dispatcher.dump(instrumentedType, false, unresolvedType.getBinaryRepresentation());
1✔
2248
            return unresolvedType.toDynamicType(typeResolutionStrategy);
1✔
2249
        }
2250

2251
        /**
2252
         * Creates an unresolved version of the dynamic type.
2253
         *
2254
         * @param typeInitializer The type initializer to use.
2255
         * @param dispatcher      A dispatcher for dumping class files.
2256
         * @return An unresolved type.
2257
         */
2258
        protected abstract UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher);
2259

2260
        /**
2261
         * An unresolved type.
2262
         */
2263
        @HashCodeAndEqualsPlugin.Enhance(includeSyntheticFields = true)
2264
        protected class UnresolvedType {
2265

2266
            /**
2267
             * The type's binary representation.
2268
             */
2269
            private final byte[] binaryRepresentation;
2270

2271
            /**
2272
             * A list of auxiliary types for this unresolved type.
2273
             */
2274
            private final List<? extends DynamicType> auxiliaryTypes;
2275

2276
            /**
2277
             * Creates a new unresolved type.
2278
             *
2279
             * @param binaryRepresentation The type's binary representation.
2280
             * @param auxiliaryTypes       A list of auxiliary types for this unresolved type.
2281
             */
2282
            protected UnresolvedType(byte[] binaryRepresentation, List<? extends DynamicType> auxiliaryTypes) {
1✔
2283
                this.binaryRepresentation = binaryRepresentation;
1✔
2284
                this.auxiliaryTypes = auxiliaryTypes;
1✔
2285
            }
1✔
2286

2287
            /**
2288
             * Resolves this type to a dynamic type.
2289
             *
2290
             * @param typeResolutionStrategy The type resolution strategy to apply.
2291
             * @return A dynamic type representing the inlined type.
2292
             */
2293
            protected DynamicType.Unloaded<S> toDynamicType(TypeResolutionStrategy.Resolved typeResolutionStrategy) {
2294
                return new DynamicType.Default.Unloaded<S>(instrumentedType,
1✔
2295
                        binaryRepresentation,
2296
                        loadedTypeInitializer,
2297
                        CompoundList.of(Default.this.auxiliaryTypes, auxiliaryTypes),
1✔
2298
                        typeResolutionStrategy);
2299
            }
2300

2301
            /**
2302
             * Returns the binary representation of this unresolved type.
2303
             *
2304
             * @return The binary representation of this unresolved type.
2305
             */
2306
            protected byte[] getBinaryRepresentation() {
2307
                return binaryRepresentation;
1✔
2308
            }
2309
        }
2310

2311
        /**
2312
         * A key to represent a unique signature.
2313
         */
2314
        protected static class SignatureKey {
2315

2316
            /**
2317
             * The represented internal name.
2318
             */
2319
            private final String internalName;
2320

2321
            /**
2322
             * The represented descriptor.
2323
             */
2324
            private final String descriptor;
2325

2326
            /**
2327
             * Creates a new signature key.
2328
             *
2329
             * @param internalName The represented internal name.
2330
             * @param descriptor   The represented descriptor.
2331
             */
2332
            public SignatureKey(String internalName, String descriptor) {
1✔
2333
                this.internalName = internalName;
1✔
2334
                this.descriptor = descriptor;
1✔
2335
            }
1✔
2336

2337
            @Override
2338
            public boolean equals(@MaybeNull Object other) {
2339
                if (this == other) return true;
1✔
2340
                if (other == null || getClass() != other.getClass()) return false;
1✔
2341
                SignatureKey that = (SignatureKey) other;
1✔
2342
                return internalName.equals(that.internalName) && descriptor.equals(that.descriptor);
1✔
2343
            }
2344

2345
            @Override
2346
            public int hashCode() {
2347
                return 17 + internalName.hashCode() + 31 * descriptor.hashCode();
1✔
2348
            }
2349
        }
2350

2351
        /**
2352
         * A class validator that validates that a class only defines members that are appropriate for the sort of the generated class.
2353
         */
2354
        protected static class ValidatingClassVisitor extends ClassVisitor {
2355

2356
            /**
2357
             * Indicates that a method has no method parameters.
2358
             */
2359
            private static final String NO_PARAMETERS = "()";
2360

2361
            /**
2362
             * Indicates that a method returns void.
2363
             */
2364
            private static final String RETURNS_VOID = "V";
2365

2366
            /**
2367
             * The descriptor of the {@link String} type.
2368
             */
2369
            private static final String STRING_DESCRIPTOR = "Ljava/lang/String;";
2370

2371
            /**
2372
             * Indicates that a field is ignored.
2373
             */
2374
            @AlwaysNull
2375
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
2376

2377
            /**
2378
             * Indicates that a method is ignored.
2379
             */
2380
            @AlwaysNull
2381
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
2382

2383
            /**
2384
             * The constraint to assert the members against. The constraint is first defined when the general class information is visited.
2385
             */
2386
            @UnknownNull
2387
            private Constraint constraint;
2388

2389
            /**
2390
             * Creates a validating class visitor.
2391
             *
2392
             * @param classVisitor The class visitor to which any calls are delegated to.
2393
             */
2394
            protected ValidatingClassVisitor(ClassVisitor classVisitor) {
2395
                super(OpenedClassReader.ASM_API, classVisitor);
1✔
2396
            }
1✔
2397

2398
            /**
2399
             * Adds a validating visitor if type validation is enabled.
2400
             *
2401
             * @param classVisitor   The original class visitor.
2402
             * @param typeValidation The type validation state.
2403
             * @return A class visitor that applies type validation if this is required.
2404
             */
2405
            protected static ClassVisitor of(ClassVisitor classVisitor, TypeValidation typeValidation) {
2406
                return typeValidation.isEnabled()
1✔
2407
                        ? new ValidatingClassVisitor(classVisitor)
2408
                        : classVisitor;
2409
            }
2410

2411
            @Override
2412
            public void visit(int version, int modifiers, String name, @MaybeNull String signature, @MaybeNull String superName, @MaybeNull String[] interfaceInternalName) {
2413
                ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(version);
1✔
2414
                List<Constraint> constraints = new ArrayList<Constraint>();
1✔
2415
                constraints.add(new Constraint.ForClassFileVersion(classFileVersion));
1✔
2416
                if (name.endsWith('/' + PackageDescription.PACKAGE_CLASS_NAME)) {
1✔
2417
                    constraints.add(Constraint.ForPackageType.INSTANCE);
1✔
2418
                } else if ((modifiers & Opcodes.ACC_ANNOTATION) != 0) {
1✔
2419
                    if (!classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
2420
                        throw new IllegalStateException("Cannot define an annotation type for class file version " + classFileVersion);
1✔
2421
                    }
2422
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2423
                            ? Constraint.ForAnnotation.JAVA_8
2424
                            : Constraint.ForAnnotation.CLASSIC);
2425
                } else if ((modifiers & Opcodes.ACC_INTERFACE) != 0) {
1✔
2426
                    constraints.add(classFileVersion.isAtLeast(ClassFileVersion.JAVA_V8)
1✔
2427
                            ? Constraint.ForInterface.JAVA_8
2428
                            : Constraint.ForInterface.CLASSIC);
2429
                } else if ((modifiers & Opcodes.ACC_ABSTRACT) != 0) {
1✔
2430
                    constraints.add(Constraint.ForClass.ABSTRACT);
1✔
2431
                } else {
2432
                    constraints.add(Constraint.ForClass.MANIFEST);
1✔
2433
                }
2434
                boolean record;
2435
                if ((modifiers & Opcodes.ACC_RECORD) != 0) {
1✔
2436
                    constraints.add(Constraint.ForRecord.INSTANCE);
1✔
2437
                    record = true;
1✔
2438
                } else {
2439
                    record = false;
1✔
2440
                }
2441
                constraint = new Constraint.Compound(constraints);
1✔
2442
                constraint.assertType(modifiers, interfaceInternalName != null, signature != null);
1✔
2443
                if (record) {
1✔
2444
                    constraint.assertRecord();
×
2445
                }
2446
                super.visit(version, modifiers, name, signature, superName, interfaceInternalName);
1✔
2447
            }
1✔
2448

2449
            @Override
2450
            public void visitPermittedSubclass(String permittedSubclass) {
2451
                constraint.assertPermittedSubclass();
×
2452
                super.visitPermittedSubclass(permittedSubclass);
×
2453
            }
×
2454

2455
            @Override
2456
            @MaybeNull
2457
            public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
2458
                constraint.assertAnnotation();
1✔
2459
                return super.visitAnnotation(descriptor, visible);
1✔
2460
            }
2461

2462
            @Override
2463
            @MaybeNull
2464
            public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
2465
                constraint.assertTypeAnnotation();
1✔
2466
                return super.visitTypeAnnotation(typeReference, typePath, descriptor, visible);
1✔
2467
            }
2468

2469
            @Override
2470
            public void visitNestHost(String nestHost) {
2471
                constraint.assertNestMate();
×
2472
                super.visitNestHost(nestHost);
×
2473
            }
×
2474

2475
            @Override
2476
            public void visitNestMember(String nestMember) {
2477
                constraint.assertNestMate();
×
2478
                super.visitNestMember(nestMember);
×
2479
            }
×
2480

2481
            @Override
2482
            @MaybeNull
2483
            public FieldVisitor visitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
2484
                if (value != null) {
1✔
2485
                    Class<?> type;
2486
                    switch (descriptor.charAt(0)) {
1✔
2487
                        case 'Z':
2488
                        case 'B':
2489
                        case 'C':
2490
                        case 'S':
2491
                        case 'I':
2492
                            type = Integer.class;
1✔
2493
                            break;
1✔
2494
                        case 'J':
2495
                            type = Long.class;
1✔
2496
                            break;
1✔
2497
                        case 'F':
2498
                            type = Float.class;
1✔
2499
                            break;
1✔
2500
                        case 'D':
2501
                            type = Double.class;
1✔
2502
                            break;
1✔
2503
                        default:
2504
                            if (!descriptor.equals(STRING_DESCRIPTOR)) {
1✔
2505
                                throw new IllegalStateException("Cannot define a default value for type of field " + name);
1✔
2506
                            }
2507
                            type = String.class;
1✔
2508
                    }
2509
                    if (!type.isInstance(value)) {
1✔
2510
                        throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value + " (" + value.getClass().getName() + ")");
1✔
2511
                    } else if (type == Integer.class) {
1✔
2512
                        boolean outOfRange;
2513
                        switch (descriptor.charAt(0)) {
1✔
2514
                            case 'Z':
2515
                                outOfRange = (Integer) value < 0 || (Integer) value > 1;
1✔
2516
                                break;
1✔
2517
                            case 'B':
2518
                                outOfRange = (Integer) value < Byte.MIN_VALUE || (Integer) value > Byte.MAX_VALUE;
1✔
2519
                                break;
1✔
2520
                            case 'S':
2521
                                outOfRange = (Integer) value < Short.MIN_VALUE || (Integer) value > Short.MAX_VALUE;
1✔
2522
                                break;
1✔
2523
                            case 'C':
2524
                                outOfRange = (Integer) value < Character.MIN_VALUE || (Integer) value > Character.MAX_VALUE;
1✔
2525
                                break;
1✔
2526
                            default:
2527
                                outOfRange = false;
1✔
2528
                        }
2529
                        if (outOfRange) {
1✔
2530
                            throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value);
1✔
2531
                        }
2532
                    }
2533
                }
2534
                constraint.assertField(name,
1✔
2535
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2536
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2537
                        (modifiers & Opcodes.ACC_FINAL) != 0,
2538
                        signature != null);
2539
                FieldVisitor fieldVisitor = super.visitField(modifiers, name, descriptor, signature, value);
1✔
2540
                return fieldVisitor == null
1✔
2541
                        ? IGNORE_FIELD
2542
                        : new ValidatingFieldVisitor(fieldVisitor);
2543
            }
2544

2545
            @Override
2546
            @MaybeNull
2547
            public MethodVisitor visitMethod(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull String[] exceptionInternalName) {
2548
                constraint.assertMethod(name,
1✔
2549
                        (modifiers & Opcodes.ACC_ABSTRACT) != 0,
2550
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2551
                        (modifiers & Opcodes.ACC_PRIVATE) != 0,
2552
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2553
                        !name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME)
1✔
2554
                                && !name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)
1✔
2555
                                && (modifiers & (Opcodes.ACC_PRIVATE | Opcodes.ACC_STATIC)) == 0,
2556
                        name.equals(MethodDescription.CONSTRUCTOR_INTERNAL_NAME),
1✔
2557
                        !descriptor.startsWith(NO_PARAMETERS) || descriptor.endsWith(RETURNS_VOID),
1✔
2558
                        signature != null);
2559
                MethodVisitor methodVisitor = super.visitMethod(modifiers, name, descriptor, signature, exceptionInternalName);
1✔
2560
                return methodVisitor == null
1✔
2561
                        ? IGNORE_METHOD
2562
                        : new ValidatingMethodVisitor(methodVisitor, name);
2563
            }
2564

2565
            /**
2566
             * A constraint for members that are legal for a given type.
2567
             */
2568
            protected interface Constraint {
2569

2570
                /**
2571
                 * Asserts if the type can legally represent a package description.
2572
                 *
2573
                 * @param modifier          The modifier that is to be written to the type.
2574
                 * @param definesInterfaces {@code true} if this type implements at least one interface.
2575
                 * @param isGeneric         {@code true} if this type defines a generic type signature.
2576
                 */
2577
                void assertType(int modifier, boolean definesInterfaces, boolean isGeneric);
2578

2579
                /**
2580
                 * Asserts a field for being valid.
2581
                 *
2582
                 * @param name      The name of the field.
2583
                 * @param isPublic  {@code true} if this field is public.
2584
                 * @param isStatic  {@code true} if this field is static.
2585
                 * @param isFinal   {@code true} if this field is final.
2586
                 * @param isGeneric {@code true} if this field defines a generic signature.
2587
                 */
2588
                void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric);
2589

2590
                /**
2591
                 * Asserts a method for being valid.
2592
                 *
2593
                 * @param name                       The name of the method.
2594
                 * @param isAbstract                 {@code true} if the method is abstract.
2595
                 * @param isPublic                   {@code true} if this method is public.
2596
                 * @param isPrivate                  {@code true} if this method is private.
2597
                 * @param isStatic                   {@code true} if this method is static.
2598
                 * @param isVirtual                  {@code true} if this method is virtual.
2599
                 * @param isConstructor              {@code true} if this method is a constructor.
2600
                 * @param isDefaultValueIncompatible {@code true} if a method's signature cannot describe an annotation property method.
2601
                 * @param isGeneric                  {@code true} if this method defines a generic signature.
2602
                 */
2603
                void assertMethod(String name,
2604
                                  boolean isAbstract,
2605
                                  boolean isPublic,
2606
                                  boolean isPrivate,
2607
                                  boolean isStatic,
2608
                                  boolean isVirtual,
2609
                                  boolean isConstructor,
2610
                                  boolean isDefaultValueIncompatible,
2611
                                  boolean isGeneric);
2612

2613
                /**
2614
                 * Asserts the legitimacy of an annotation for the instrumented type.
2615
                 */
2616
                void assertAnnotation();
2617

2618
                /**
2619
                 * Asserts the legitimacy of a type annotation for the instrumented type.
2620
                 */
2621
                void assertTypeAnnotation();
2622

2623
                /**
2624
                 * Asserts if a default value is legal for a method.
2625
                 *
2626
                 * @param name The name of the method.
2627
                 */
2628
                void assertDefaultValue(String name);
2629

2630
                /**
2631
                 * Asserts if it is legal to invoke a default method from a type.
2632
                 */
2633
                void assertDefaultMethodCall();
2634

2635
                /**
2636
                 * Asserts the capability to store a type constant in the class's constant pool.
2637
                 */
2638
                void assertTypeInConstantPool();
2639

2640
                /**
2641
                 * Asserts the capability to store a method type constant in the class's constant pool.
2642
                 */
2643
                void assertMethodTypeInConstantPool();
2644

2645
                /**
2646
                 * Asserts the capability to store a method handle in the class's constant pool.
2647
                 */
2648
                void assertHandleInConstantPool();
2649

2650
                /**
2651
                 * Asserts the capability to invoke a method dynamically.
2652
                 */
2653
                void assertInvokeDynamic();
2654

2655
                /**
2656
                 * Asserts the capability of executing a subroutine.
2657
                 */
2658
                void assertSubRoutine();
2659

2660
                /**
2661
                 * Asserts the capability of storing a dynamic value in the constant pool.
2662
                 */
2663
                void assertDynamicValueInConstantPool();
2664

2665
                /**
2666
                 * Asserts the capability of storing nest mate information.
2667
                 */
2668
                void assertNestMate();
2669

2670
                /**
2671
                 * Asserts the presence of a record component.
2672
                 */
2673
                void assertRecord();
2674

2675
                /**
2676
                 * Asserts the presence of a permitted subclass.
2677
                 */
2678
                void assertPermittedSubclass();
2679

2680
                /**
2681
                 * Represents the constraint of a class type.
2682
                 */
2683
                enum ForClass implements Constraint {
1✔
2684

2685
                    /**
2686
                     * Represents the constraints of a non-abstract class.
2687
                     */
2688
                    MANIFEST(true),
1✔
2689

2690
                    /**
2691
                     * Represents the constraints of an abstract class.
2692
                     */
2693
                    ABSTRACT(false);
1✔
2694

2695
                    /**
2696
                     * {@code true} if this instance represents the constraints a non-abstract class.
2697
                     */
2698
                    private final boolean manifestType;
2699

2700
                    /**
2701
                     * Creates a new constraint for a class.
2702
                     *
2703
                     * @param manifestType {@code true} if this instance represents a non-abstract class.
2704
                     */
2705
                    ForClass(boolean manifestType) {
1✔
2706
                        this.manifestType = manifestType;
1✔
2707
                    }
1✔
2708

2709
                    /**
2710
                     * {@inheritDoc}
2711
                     */
2712
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2713
                        /* do nothing */
2714
                    }
1✔
2715

2716
                    /**
2717
                     * {@inheritDoc}
2718
                     */
2719
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2720
                        /* do nothing */
2721
                    }
1✔
2722

2723
                    /**
2724
                     * {@inheritDoc}
2725
                     */
2726
                    public void assertMethod(String name,
2727
                                             boolean isAbstract,
2728
                                             boolean isPublic,
2729
                                             boolean isPrivate,
2730
                                             boolean isStatic,
2731
                                             boolean isVirtual,
2732
                                             boolean isConstructor,
2733
                                             boolean isDefaultValueIncompatible,
2734
                                             boolean isGeneric) {
2735
                        if (isAbstract && manifestType) {
1✔
2736
                            throw new IllegalStateException("Cannot define abstract method '" + name + "' for non-abstract class");
1✔
2737
                        }
2738
                    }
1✔
2739

2740
                    /**
2741
                     * {@inheritDoc}
2742
                     */
2743
                    public void assertAnnotation() {
2744
                        /* do nothing */
2745
                    }
1✔
2746

2747
                    /**
2748
                     * {@inheritDoc}
2749
                     */
2750
                    public void assertTypeAnnotation() {
2751
                        /* do nothing */
2752
                    }
1✔
2753

2754
                    /**
2755
                     * {@inheritDoc}
2756
                     */
2757
                    public void assertDefaultValue(String name) {
2758
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
1✔
2759
                    }
2760

2761
                    /**
2762
                     * {@inheritDoc}
2763
                     */
2764
                    public void assertDefaultMethodCall() {
2765
                        /* do nothing */
2766
                    }
1✔
2767

2768
                    /**
2769
                     * {@inheritDoc}
2770
                     */
2771
                    public void assertTypeInConstantPool() {
2772
                        /* do nothing */
2773
                    }
1✔
2774

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

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

2789
                    /**
2790
                     * {@inheritDoc}
2791
                     */
2792
                    public void assertInvokeDynamic() {
2793
                        /* do nothing */
2794
                    }
1✔
2795

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

2803
                    /**
2804
                     * {@inheritDoc}
2805
                     */
2806
                    public void assertDynamicValueInConstantPool() {
2807
                        /* do nothing */
2808
                    }
×
2809

2810
                    /**
2811
                     * {@inheritDoc}
2812
                     */
2813
                    public void assertNestMate() {
2814
                        /* do nothing */
2815
                    }
×
2816

2817
                    /**
2818
                     * {@inheritDoc}
2819
                     */
2820
                    public void assertRecord() {
2821
                        /* do nothing */
2822
                    }
×
2823

2824
                    /**
2825
                     * {@inheritDoc}
2826
                     */
2827
                    public void assertPermittedSubclass() {
2828
                        /* do nothing */
2829
                    }
×
2830
                }
2831

2832
                /**
2833
                 * Represents the constraint of a package type.
2834
                 */
2835
                enum ForPackageType implements Constraint {
1✔
2836

2837
                    /**
2838
                     * The singleton instance.
2839
                     */
2840
                    INSTANCE;
1✔
2841

2842
                    /**
2843
                     * {@inheritDoc}
2844
                     */
2845
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2846
                        throw new IllegalStateException("Cannot define a field for a package description type");
1✔
2847
                    }
2848

2849
                    /**
2850
                     * {@inheritDoc}
2851
                     */
2852
                    public void assertMethod(String name,
2853
                                             boolean isAbstract,
2854
                                             boolean isPublic,
2855
                                             boolean isPrivate,
2856
                                             boolean isStatic,
2857
                                             boolean isVirtual,
2858
                                             boolean isConstructor,
2859
                                             boolean isNoDefaultValue,
2860
                                             boolean isGeneric) {
2861
                        throw new IllegalStateException("Cannot define a method for a package description type");
×
2862
                    }
2863

2864
                    /**
2865
                     * {@inheritDoc}
2866
                     */
2867
                    public void assertAnnotation() {
2868
                        /* do nothing */
2869
                    }
1✔
2870

2871
                    /**
2872
                     * {@inheritDoc}
2873
                     */
2874
                    public void assertTypeAnnotation() {
2875
                        /* do nothing */
2876
                    }
×
2877

2878
                    /**
2879
                     * {@inheritDoc}
2880
                     */
2881
                    public void assertDefaultValue(String name) {
2882
                        /* do nothing, implicit by forbidding methods */
2883
                    }
×
2884

2885
                    /**
2886
                     * {@inheritDoc}
2887
                     */
2888
                    public void assertDefaultMethodCall() {
2889
                        /* do nothing */
2890
                    }
×
2891

2892
                    /**
2893
                     * {@inheritDoc}
2894
                     */
2895
                    public void assertTypeInConstantPool() {
2896
                        /* do nothing */
2897
                    }
×
2898

2899
                    /**
2900
                     * {@inheritDoc}
2901
                     */
2902
                    public void assertMethodTypeInConstantPool() {
2903
                        /* do nothing */
2904
                    }
×
2905

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

2913
                    /**
2914
                     * {@inheritDoc}
2915
                     */
2916
                    public void assertInvokeDynamic() {
2917
                        /* do nothing */
2918
                    }
×
2919

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

2927
                    /**
2928
                     * {@inheritDoc}
2929
                     */
2930
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2931
                        if (modifier != PackageDescription.PACKAGE_MODIFIERS) {
1✔
2932
                            throw new IllegalStateException("A package description type must define " + PackageDescription.PACKAGE_MODIFIERS + " as modifier");
×
2933
                        } else if (definesInterfaces) {
1✔
2934
                            throw new IllegalStateException("Cannot implement interface for package type");
1✔
2935
                        }
2936
                    }
1✔
2937

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

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

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

2959
                    /**
2960
                     * {@inheritDoc}
2961
                     */
2962
                    public void assertPermittedSubclass() {
2963
                        /* do nothing */
2964
                    }
×
2965
                }
2966

2967
                /**
2968
                 * Represents the constraint of an interface type.
2969
                 */
2970
                enum ForInterface implements Constraint {
1✔
2971

2972
                    /**
2973
                     * An interface type with the constraints for the Java versions 5 to 7.
2974
                     */
2975
                    CLASSIC(true),
1✔
2976

2977
                    /**
2978
                     * An interface type with the constraints for the Java versions 8+.
2979
                     */
2980
                    JAVA_8(false);
1✔
2981

2982
                    /**
2983
                     * {@code true} if this instance represents a classic interface type (pre Java 8).
2984
                     */
2985
                    private final boolean classic;
2986

2987
                    /**
2988
                     * Creates a constraint for an interface type.
2989
                     *
2990
                     * @param classic {@code true} if this instance represents a classic interface (pre Java 8).
2991
                     */
2992
                    ForInterface(boolean classic) {
1✔
2993
                        this.classic = classic;
1✔
2994
                    }
1✔
2995

2996
                    /**
2997
                     * {@inheritDoc}
2998
                     */
2999
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3000
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3001
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3002
                        }
3003
                    }
1✔
3004

3005
                    /**
3006
                     * {@inheritDoc}
3007
                     */
3008
                    public void assertMethod(String name,
3009
                                             boolean isAbstract,
3010
                                             boolean isPublic,
3011
                                             boolean isPrivate,
3012
                                             boolean isStatic,
3013
                                             boolean isVirtual,
3014
                                             boolean isConstructor,
3015
                                             boolean isDefaultValueIncompatible,
3016
                                             boolean isGeneric) {
3017
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3018
                            if (isConstructor) {
1✔
3019
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3020
                            } else if (classic && !isPublic) {
1✔
3021
                                throw new IllegalStateException("Cannot define non-public method '" + name + "' for interface type");
×
3022
                            } else if (classic && !isVirtual) {
1✔
3023
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 interface type");
×
3024
                            } else if (classic && !isAbstract) {
1✔
3025
                                throw new IllegalStateException("Cannot define default method '" + name + "' for pre-Java 8 interface type");
×
3026
                            }
3027
                        }
3028
                    }
1✔
3029

3030
                    /**
3031
                     * {@inheritDoc}
3032
                     */
3033
                    public void assertAnnotation() {
3034
                        /* do nothing */
3035
                    }
1✔
3036

3037
                    /**
3038
                     * {@inheritDoc}
3039
                     */
3040
                    public void assertTypeAnnotation() {
3041
                        /* do nothing */
3042
                    }
×
3043

3044
                    /**
3045
                     * {@inheritDoc}
3046
                     */
3047
                    public void assertDefaultValue(String name) {
3048
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
×
3049
                    }
3050

3051
                    /**
3052
                     * {@inheritDoc}
3053
                     */
3054
                    public void assertDefaultMethodCall() {
3055
                        /* do nothing */
3056
                    }
1✔
3057

3058
                    /**
3059
                     * {@inheritDoc}
3060
                     */
3061
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3062
                        /* do nothing */
3063
                    }
1✔
3064

3065
                    /**
3066
                     * {@inheritDoc}
3067
                     */
3068
                    public void assertTypeInConstantPool() {
3069
                        /* do nothing */
3070
                    }
×
3071

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

3079
                    /**
3080
                     * {@inheritDoc}
3081
                     */
3082
                    public void assertHandleInConstantPool() {
3083
                        /* do nothing */
3084
                    }
×
3085

3086
                    /**
3087
                     * {@inheritDoc}
3088
                     */
3089
                    public void assertInvokeDynamic() {
3090
                        /* do nothing */
3091
                    }
×
3092

3093
                    /**
3094
                     * {@inheritDoc}
3095
                     */
3096
                    public void assertSubRoutine() {
3097
                        /* do nothing */
3098
                    }
×
3099

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

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

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

3121
                    /**
3122
                     * {@inheritDoc}
3123
                     */
3124
                    public void assertPermittedSubclass() {
3125
                        /* do nothing */
3126
                    }
×
3127
                }
3128

3129
                /**
3130
                 * Represents the constraint of a record type.
3131
                 */
3132
                enum ForRecord implements Constraint {
1✔
3133

3134
                    /**
3135
                     * The singleton instance.
3136
                     */
3137
                    INSTANCE;
1✔
3138

3139
                    /**
3140
                     * {@inheritDoc}
3141
                     */
3142
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3143
                        /* do nothing */
3144
                    }
×
3145

3146
                    /**
3147
                     * {@inheritDoc}
3148
                     */
3149
                    public void assertMethod(String name,
3150
                                             boolean isAbstract,
3151
                                             boolean isPublic,
3152
                                             boolean isPrivate,
3153
                                             boolean isStatic,
3154
                                             boolean isVirtual,
3155
                                             boolean isConstructor,
3156
                                             boolean isDefaultValueIncompatible,
3157
                                             boolean isGeneric) {
3158
                        /* do nothing */
3159
                    }
×
3160

3161
                    /**
3162
                     * {@inheritDoc}
3163
                     */
3164
                    public void assertAnnotation() {
3165
                        /* do nothing */
3166
                    }
×
3167

3168
                    /**
3169
                     * {@inheritDoc}
3170
                     */
3171
                    public void assertTypeAnnotation() {
3172
                        /* do nothing */
3173
                    }
×
3174

3175
                    /**
3176
                     * {@inheritDoc}
3177
                     */
3178
                    public void assertDefaultValue(String name) {
3179
                        /* do nothing */
3180
                    }
×
3181

3182
                    /**
3183
                     * {@inheritDoc}
3184
                     */
3185
                    public void assertDefaultMethodCall() {
3186
                        /* do nothing */
3187
                    }
×
3188

3189
                    /**
3190
                     * {@inheritDoc}
3191
                     */
3192
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3193
                        if ((modifier & Opcodes.ACC_ABSTRACT) != 0) {
1✔
3194
                            throw new IllegalStateException("Cannot define a record class as abstract");
×
3195
                        }
3196
                    }
1✔
3197

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

3205
                    /**
3206
                     * {@inheritDoc}
3207
                     */
3208
                    public void assertMethodTypeInConstantPool() {
3209
                        /* do nothing */
3210
                    }
×
3211

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

3219
                    /**
3220
                     * {@inheritDoc}
3221
                     */
3222
                    public void assertInvokeDynamic() {
3223
                        /* do nothing */
3224
                    }
×
3225

3226
                    /**
3227
                     * {@inheritDoc}
3228
                     */
3229
                    public void assertSubRoutine() {
3230
                        /* do nothing */
3231
                    }
×
3232

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

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

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

3254
                    /**
3255
                     * {@inheritDoc}
3256
                     */
3257
                    public void assertPermittedSubclass() {
3258
                        /* do nothing */
3259
                    }
×
3260
                }
3261

3262
                /**
3263
                 * Represents the constraint of an annotation type.
3264
                 */
3265
                enum ForAnnotation implements Constraint {
1✔
3266

3267
                    /**
3268
                     * An annotation type with the constraints for the Java versions 5 to 7.
3269
                     */
3270
                    CLASSIC(true),
1✔
3271

3272
                    /**
3273
                     * An annotation type with the constraints for the Java versions 8+.
3274
                     */
3275
                    JAVA_8(false);
1✔
3276

3277
                    /**
3278
                     * {@code true} if this instance represents a classic annotation type (pre Java 8).
3279
                     */
3280
                    private final boolean classic;
3281

3282
                    /**
3283
                     * Creates a constraint for an annotation type.
3284
                     *
3285
                     * @param classic {@code true} if this instance represents a classic annotation type (pre Java 8).
3286
                     */
3287
                    ForAnnotation(boolean classic) {
1✔
3288
                        this.classic = classic;
1✔
3289
                    }
1✔
3290

3291
                    /**
3292
                     * {@inheritDoc}
3293
                     */
3294
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3295
                        if (!isStatic || !isPublic || !isFinal) {
1✔
3296
                            throw new IllegalStateException("Cannot only define public, static, final field '" + name + "' for interface type");
1✔
3297
                        }
3298
                    }
×
3299

3300
                    /**
3301
                     * {@inheritDoc}
3302
                     */
3303
                    public void assertMethod(String name,
3304
                                             boolean isAbstract,
3305
                                             boolean isPublic,
3306
                                             boolean isPrivate,
3307
                                             boolean isStatic,
3308
                                             boolean isVirtual,
3309
                                             boolean isConstructor,
3310
                                             boolean isDefaultValueIncompatible,
3311
                                             boolean isGeneric) {
3312
                        if (!name.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
3313
                            if (isConstructor) {
1✔
3314
                                throw new IllegalStateException("Cannot define constructor for interface type");
1✔
3315
                            } else if (classic && !isVirtual) {
1✔
3316
                                throw new IllegalStateException("Cannot define non-virtual method '" + name + "' for a pre-Java 8 annotation type");
1✔
3317
                            } else if (!isStatic && isDefaultValueIncompatible) {
1✔
3318
                                throw new IllegalStateException("Cannot define method '" + name + "' with the given signature as an annotation type method");
1✔
3319
                            }
3320
                        }
3321
                    }
1✔
3322

3323
                    /**
3324
                     * {@inheritDoc}
3325
                     */
3326
                    public void assertAnnotation() {
3327
                        /* do nothing */
3328
                    }
1✔
3329

3330
                    /**
3331
                     * {@inheritDoc}
3332
                     */
3333
                    public void assertTypeAnnotation() {
3334
                        /* do nothing */
3335
                    }
×
3336

3337
                    /**
3338
                     * {@inheritDoc}
3339
                     */
3340
                    public void assertDefaultValue(String name) {
3341
                        /* do nothing */
3342
                    }
1✔
3343

3344
                    /**
3345
                     * {@inheritDoc}
3346
                     */
3347
                    public void assertDefaultMethodCall() {
3348
                        /* do nothing */
3349
                    }
×
3350

3351
                    /**
3352
                     * {@inheritDoc}
3353
                     */
3354
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3355
                        if ((modifier & Opcodes.ACC_INTERFACE) == 0) {
1✔
3356
                            throw new IllegalStateException("Cannot define annotation type without interface modifier");
×
3357
                        }
3358
                    }
1✔
3359

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

3367
                    /**
3368
                     * {@inheritDoc}
3369
                     */
3370
                    public void assertMethodTypeInConstantPool() {
3371
                        /* do nothing */
3372
                    }
×
3373

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

3381
                    /**
3382
                     * {@inheritDoc}
3383
                     */
3384
                    public void assertInvokeDynamic() {
3385
                        /* do nothing */
3386
                    }
×
3387

3388
                    /**
3389
                     * {@inheritDoc}
3390
                     */
3391
                    public void assertSubRoutine() {
3392
                        /* do nothing */
3393
                    }
×
3394

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

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

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

3416
                    /**
3417
                     * {@inheritDoc}
3418
                     */
3419
                    public void assertPermittedSubclass() {
3420
                        /* do nothing */
3421
                    }
×
3422
                }
3423

3424
                /**
3425
                 * Represents the constraint implied by a class file version.
3426
                 */
3427
                @HashCodeAndEqualsPlugin.Enhance
3428
                class ForClassFileVersion implements Constraint {
3429

3430
                    /**
3431
                     * The enforced class file version.
3432
                     */
3433
                    private final ClassFileVersion classFileVersion;
3434

3435
                    /**
3436
                     * Creates a new constraint for the given class file version.
3437
                     *
3438
                     * @param classFileVersion The enforced class file version.
3439
                     */
3440
                    protected ForClassFileVersion(ClassFileVersion classFileVersion) {
1✔
3441
                        this.classFileVersion = classFileVersion;
1✔
3442
                    }
1✔
3443

3444
                    /**
3445
                     * {@inheritDoc}
3446
                     */
3447
                    public void assertType(int modifiers, boolean definesInterfaces, boolean isGeneric) {
3448
                        if ((modifiers & Opcodes.ACC_ANNOTATION) != 0 && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V5)) {
1✔
3449
                            throw new IllegalStateException("Cannot define annotation type for class file version " + classFileVersion);
×
3450
                        } else if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3451
                            throw new IllegalStateException("Cannot define a generic type for class file version " + classFileVersion);
×
3452
                        }
3453
                    }
1✔
3454

3455
                    /**
3456
                     * {@inheritDoc}
3457
                     */
3458
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3459
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3460
                            throw new IllegalStateException("Cannot define generic field '" + name + "' for class file version " + classFileVersion);
×
3461
                        }
3462
                    }
1✔
3463

3464
                    /**
3465
                     * {@inheritDoc}
3466
                     */
3467
                    public void assertMethod(String name,
3468
                                             boolean isAbstract,
3469
                                             boolean isPublic,
3470
                                             boolean isPrivate,
3471
                                             boolean isStatic,
3472
                                             boolean isVirtual,
3473
                                             boolean isConstructor,
3474
                                             boolean isDefaultValueIncompatible,
3475
                                             boolean isGeneric) {
3476
                        if (isGeneric && !classFileVersion.isAtLeast(ClassFileVersion.JAVA_V4)) { // JSR14 allows for generic 1.4 classes.
1✔
3477
                            throw new IllegalStateException("Cannot define generic method '" + name + "' for class file version " + classFileVersion);
×
3478
                        } else if (!isVirtual && isAbstract) {
1✔
3479
                            throw new IllegalStateException("Cannot define static or non-virtual method '" + name + "' to be abstract");
1✔
3480
                        }
3481
                    }
1✔
3482

3483
                    /**
3484
                     * {@inheritDoc}
3485
                     */
3486
                    public void assertAnnotation() {
3487
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3488
                            throw new IllegalStateException("Cannot write annotations for class file version " + classFileVersion);
1✔
3489
                        }
3490
                    }
1✔
3491

3492
                    /**
3493
                     * {@inheritDoc}
3494
                     */
3495
                    public void assertTypeAnnotation() {
3496
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3497
                            throw new IllegalStateException("Cannot write type annotations for class file version " + classFileVersion);
×
3498
                        }
3499
                    }
1✔
3500

3501
                    /**
3502
                     * {@inheritDoc}
3503
                     */
3504
                    public void assertDefaultValue(String name) {
3505
                        /* do nothing, implicitly checked by type assertion */
3506
                    }
1✔
3507

3508
                    /**
3509
                     * {@inheritDoc}
3510
                     */
3511
                    public void assertDefaultMethodCall() {
3512
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V8)) {
1✔
3513
                            throw new IllegalStateException("Cannot invoke default method for class file version " + classFileVersion);
×
3514
                        }
3515
                    }
1✔
3516

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

3526
                    /**
3527
                     * {@inheritDoc}
3528
                     */
3529
                    public void assertMethodTypeInConstantPool() {
3530
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3531
                            throw new IllegalStateException("Cannot write method type to constant pool for class file version " + classFileVersion);
1✔
3532
                        }
3533
                    }
1✔
3534

3535
                    /**
3536
                     * {@inheritDoc}
3537
                     */
3538
                    public void assertHandleInConstantPool() {
3539
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3540
                            throw new IllegalStateException("Cannot write method handle to constant pool for class file version " + classFileVersion);
1✔
3541
                        }
3542
                    }
1✔
3543

3544
                    /**
3545
                     * {@inheritDoc}
3546
                     */
3547
                    public void assertInvokeDynamic() {
3548
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3549
                            throw new IllegalStateException("Cannot write invoke dynamic instruction for class file version " + classFileVersion);
×
3550
                        }
3551
                    }
1✔
3552

3553
                    /**
3554
                     * {@inheritDoc}
3555
                     */
3556
                    public void assertSubRoutine() {
3557
                        if (classFileVersion.isGreaterThan(ClassFileVersion.JAVA_V5)) {
1✔
3558
                            throw new IllegalStateException("Cannot write subroutine for class file version " + classFileVersion);
×
3559
                        }
3560
                    }
1✔
3561

3562
                    /**
3563
                     * {@inheritDoc}
3564
                     */
3565
                    public void assertDynamicValueInConstantPool() {
3566
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
1✔
3567
                            throw new IllegalStateException("Cannot write dynamic constant for class file version " + classFileVersion);
1✔
3568
                        }
3569
                    }
×
3570

3571
                    /**
3572
                     * {@inheritDoc}
3573
                     */
3574
                    public void assertNestMate() {
3575
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
×
3576
                            throw new IllegalStateException("Cannot define nest mate for class file version " + classFileVersion);
×
3577
                        }
3578
                    }
×
3579

3580
                    /**
3581
                     * {@inheritDoc}
3582
                     */
3583
                    public void assertRecord() {
3584
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V14)) {
1✔
3585
                            throw new IllegalStateException("Cannot define record for class file version " + classFileVersion);
1✔
3586
                        }
3587
                    }
×
3588

3589
                    /**
3590
                     * {@inheritDoc}
3591
                     */
3592
                    public void assertPermittedSubclass() {
3593
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V17)) {
×
3594
                            throw new IllegalStateException("Cannot define permitted subclasses for class file version " + classFileVersion);
×
3595
                        }
3596
                    }
×
3597
                }
3598

3599
                /**
3600
                 * A constraint implementation that summarizes several constraints.
3601
                 */
3602
                @HashCodeAndEqualsPlugin.Enhance
3603
                class Compound implements Constraint {
3604

3605
                    /**
3606
                     * A list of constraints that is enforced in the given order.
3607
                     */
3608
                    private final List<Constraint> constraints;
3609

3610
                    /**
3611
                     * Creates a new compound constraint.
3612
                     *
3613
                     * @param constraints A list of constraints that is enforced in the given order.
3614
                     */
3615
                    public Compound(List<? extends Constraint> constraints) {
1✔
3616
                        this.constraints = new ArrayList<Constraint>();
1✔
3617
                        for (Constraint constraint : constraints) {
1✔
3618
                            if (constraint instanceof Compound) {
1✔
3619
                                this.constraints.addAll(((Compound) constraint).constraints);
×
3620
                            } else {
3621
                                this.constraints.add(constraint);
1✔
3622
                            }
3623
                        }
1✔
3624
                    }
1✔
3625

3626
                    /**
3627
                     * {@inheritDoc}
3628
                     */
3629
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3630
                        for (Constraint constraint : constraints) {
1✔
3631
                            constraint.assertType(modifier, definesInterfaces, isGeneric);
1✔
3632
                        }
1✔
3633
                    }
1✔
3634

3635
                    /**
3636
                     * {@inheritDoc}
3637
                     */
3638
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3639
                        for (Constraint constraint : constraints) {
1✔
3640
                            constraint.assertField(name, isPublic, isStatic, isFinal, isGeneric);
1✔
3641
                        }
1✔
3642
                    }
1✔
3643

3644
                    /**
3645
                     * {@inheritDoc}
3646
                     */
3647
                    public void assertMethod(String name,
3648
                                             boolean isAbstract,
3649
                                             boolean isPublic,
3650
                                             boolean isPrivate,
3651
                                             boolean isStatic,
3652
                                             boolean isVirtual,
3653
                                             boolean isConstructor,
3654
                                             boolean isDefaultValueIncompatible,
3655
                                             boolean isGeneric) {
3656
                        for (Constraint constraint : constraints) {
1✔
3657
                            constraint.assertMethod(name,
1✔
3658
                                    isAbstract,
3659
                                    isPublic,
3660
                                    isPrivate,
3661
                                    isStatic,
3662
                                    isVirtual,
3663
                                    isConstructor,
3664
                                    isDefaultValueIncompatible,
3665
                                    isGeneric);
3666
                        }
1✔
3667
                    }
1✔
3668

3669
                    /**
3670
                     * {@inheritDoc}
3671
                     */
3672
                    public void assertDefaultValue(String name) {
3673
                        for (Constraint constraint : constraints) {
1✔
3674
                            constraint.assertDefaultValue(name);
1✔
3675
                        }
1✔
3676
                    }
1✔
3677

3678
                    /**
3679
                     * {@inheritDoc}
3680
                     */
3681
                    public void assertDefaultMethodCall() {
3682
                        for (Constraint constraint : constraints) {
1✔
3683
                            constraint.assertDefaultMethodCall();
1✔
3684
                        }
1✔
3685
                    }
1✔
3686

3687
                    /**
3688
                     * {@inheritDoc}
3689
                     */
3690
                    public void assertAnnotation() {
3691
                        for (Constraint constraint : constraints) {
1✔
3692
                            constraint.assertAnnotation();
1✔
3693
                        }
1✔
3694
                    }
1✔
3695

3696
                    /**
3697
                     * {@inheritDoc}
3698
                     */
3699
                    public void assertTypeAnnotation() {
3700
                        for (Constraint constraint : constraints) {
1✔
3701
                            constraint.assertTypeAnnotation();
1✔
3702
                        }
1✔
3703
                    }
1✔
3704

3705
                    /**
3706
                     * {@inheritDoc}
3707
                     */
3708
                    public void assertTypeInConstantPool() {
3709
                        for (Constraint constraint : constraints) {
1✔
3710
                            constraint.assertTypeInConstantPool();
1✔
3711
                        }
1✔
3712
                    }
1✔
3713

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

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

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

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

3750
                    /**
3751
                     * {@inheritDoc}
3752
                     */
3753
                    public void assertDynamicValueInConstantPool() {
3754
                        for (Constraint constraint : constraints) {
1✔
3755
                            constraint.assertDynamicValueInConstantPool();
×
3756
                        }
×
3757
                    }
×
3758

3759
                    /**
3760
                     * {@inheritDoc}
3761
                     */
3762
                    public void assertNestMate() {
3763
                        for (Constraint constraint : constraints) {
×
3764
                            constraint.assertNestMate();
×
3765
                        }
×
3766
                    }
×
3767

3768
                    /**
3769
                     * {@inheritDoc}
3770
                     */
3771
                    public void assertRecord() {
3772
                        for (Constraint constraint : constraints) {
1✔
3773
                            constraint.assertRecord();
×
3774
                        }
×
3775
                    }
×
3776

3777
                    /**
3778
                     * {@inheritDoc}
3779
                     */
3780
                    public void assertPermittedSubclass() {
3781
                        for (Constraint constraint : constraints) {
×
3782
                            constraint.assertPermittedSubclass();
×
3783
                        }
×
3784
                    }
×
3785
                }
3786
            }
3787

3788
            /**
3789
             * A field validator for checking default values.
3790
             */
3791
            protected class ValidatingFieldVisitor extends FieldVisitor {
3792

3793
                /**
3794
                 * Creates a validating field visitor.
3795
                 *
3796
                 * @param fieldVisitor The field visitor to which any calls are delegated to.
3797
                 */
3798
                protected ValidatingFieldVisitor(FieldVisitor fieldVisitor) {
1✔
3799
                    super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
3800
                }
1✔
3801

3802
                @Override
3803
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3804
                    constraint.assertAnnotation();
1✔
3805
                    return super.visitAnnotation(descriptor, visible);
1✔
3806
                }
3807
            }
3808

3809
            /**
3810
             * A method validator for checking default values.
3811
             */
3812
            protected class ValidatingMethodVisitor extends MethodVisitor {
3813

3814
                /**
3815
                 * The name of the method being visited.
3816
                 */
3817
                private final String name;
3818

3819
                /**
3820
                 * Creates a validating method visitor.
3821
                 *
3822
                 * @param methodVisitor The method visitor to which any calls are delegated to.
3823
                 * @param name          The name of the method being visited.
3824
                 */
3825
                protected ValidatingMethodVisitor(MethodVisitor methodVisitor, String name) {
1✔
3826
                    super(OpenedClassReader.ASM_API, methodVisitor);
1✔
3827
                    this.name = name;
1✔
3828
                }
1✔
3829

3830
                @Override
3831
                @MaybeNull
3832
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3833
                    constraint.assertAnnotation();
1✔
3834
                    return super.visitAnnotation(descriptor, visible);
1✔
3835
                }
3836

3837
                @Override
3838
                @MaybeNull
3839
                public AnnotationVisitor visitAnnotationDefault() {
3840
                    constraint.assertDefaultValue(name);
1✔
3841
                    return super.visitAnnotationDefault();
1✔
3842
                }
3843

3844
                @Override
3845
                @SuppressFBWarnings(value = "SF_SWITCH_NO_DEFAULT", justification = "Fall through to default case is intentional.")
3846
                public void visitLdcInsn(Object value) {
3847
                    if (value instanceof Type) {
1✔
3848
                        Type type = (Type) value;
1✔
3849
                        switch (type.getSort()) {
1✔
3850
                            case Type.OBJECT:
3851
                            case Type.ARRAY:
3852
                                constraint.assertTypeInConstantPool();
1✔
3853
                                break;
1✔
3854
                            case Type.METHOD:
3855
                                constraint.assertMethodTypeInConstantPool();
1✔
3856
                                break;
3857
                        }
3858
                    } else if (value instanceof Handle) {
1✔
3859
                        constraint.assertHandleInConstantPool();
1✔
3860
                    } else if (value instanceof ConstantDynamic) {
1✔
3861
                        constraint.assertDynamicValueInConstantPool();
×
3862
                    }
3863
                    super.visitLdcInsn(value);
1✔
3864
                }
1✔
3865

3866
                @Override
3867
                public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
3868
                    if (isInterface && opcode == Opcodes.INVOKESPECIAL) {
1✔
3869
                        constraint.assertDefaultMethodCall();
1✔
3870
                    }
3871
                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
1✔
3872
                }
1✔
3873

3874
                @Override
3875
                public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethod, Object... bootstrapArgument) {
3876
                    constraint.assertInvokeDynamic();
1✔
3877
                    for (Object constant : bootstrapArgument) {
1✔
3878
                        if (constant instanceof ConstantDynamic) {
1✔
3879
                            constraint.assertDynamicValueInConstantPool();
×
3880
                        }
3881
                    }
3882
                    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethod, bootstrapArgument);
1✔
3883
                }
1✔
3884

3885
                @Override
3886
                public void visitJumpInsn(int opcode, Label label) {
3887
                    if (opcode == Opcodes.JSR) {
1✔
3888
                        constraint.assertSubRoutine();
1✔
3889
                    }
3890
                    super.visitJumpInsn(opcode, label);
1✔
3891
                }
1✔
3892
            }
3893
        }
3894

3895
        /**
3896
         * A type writer that inlines the created type into an existing class file.
3897
         *
3898
         * @param <U> The best known loaded type for the dynamically created type.
3899
         */
3900
        @HashCodeAndEqualsPlugin.Enhance
3901
        public abstract static class ForInlining<U> extends Default<U> {
3902

3903
            /**
3904
             * Indicates that a field should be ignored.
3905
             */
3906
            @AlwaysNull
3907
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
3908

3909
            /**
3910
             * Indicates that a method should be ignored.
3911
             */
3912
            @AlwaysNull
3913
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
3914

3915
            /**
3916
             * Indicates that a record component should be ignored.
3917
             */
3918
            @AlwaysNull
3919
            private static final RecordComponentVisitor IGNORE_RECORD_COMPONENT = null;
1✔
3920

3921
            /**
3922
             * Indicates that an annotation should be ignored.
3923
             */
3924
            @AlwaysNull
3925
            private static final AnnotationVisitor IGNORE_ANNOTATION = null;
1✔
3926

3927
            /**
3928
             * The original type's description.
3929
             */
3930
            protected final TypeDescription originalType;
3931

3932
            /**
3933
             * The class file locator for locating the original type's class file.
3934
             */
3935
            protected final ClassFileLocator classFileLocator;
3936

3937
            /**
3938
             * Creates a new inlining type writer.
3939
             *
3940
             * @param instrumentedType             The instrumented type to be created.
3941
             * @param classFileVersion             The class file specified by the user.
3942
             * @param fieldPool                    The field pool to use.
3943
             * @param recordComponentPool          The record component pool to use.
3944
             * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
3945
             * @param fields                       The instrumented type's declared fields.
3946
             * @param methods                      The instrumented type's declared and virtually inherited methods.
3947
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
3948
             * @param recordComponents             The instrumented type's record components.
3949
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
3950
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
3951
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
3952
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
3953
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
3954
             * @param annotationRetention          The annotation retention to apply.
3955
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
3956
             * @param implementationContextFactory The implementation context factory to apply.
3957
             * @param typeValidation               Determines if a type should be explicitly validated.
3958
             * @param classReaderFactory           The class reader factory to use.
3959
             * @param classWriterFactory           The class writer factory to use.
3960
             * @param typePool                     The type pool to use for computing stack map frames, if required.
3961
             * @param originalType                 The original type's description.
3962
             * @param classFileLocator             The class file locator for locating the original type's class file.
3963
             */
3964
            protected ForInlining(TypeDescription instrumentedType,
3965
                                  ClassFileVersion classFileVersion,
3966
                                  FieldPool fieldPool,
3967
                                  RecordComponentPool recordComponentPool,
3968
                                  List<? extends DynamicType> auxiliaryTypes,
3969
                                  FieldList<FieldDescription.InDefinedShape> fields,
3970
                                  MethodList<?> methods,
3971
                                  MethodList<?> instrumentedMethods,
3972
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
3973
                                  LoadedTypeInitializer loadedTypeInitializer,
3974
                                  TypeInitializer typeInitializer,
3975
                                  TypeAttributeAppender typeAttributeAppender,
3976
                                  AsmVisitorWrapper asmVisitorWrapper,
3977
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
3978
                                  AnnotationRetention annotationRetention,
3979
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
3980
                                  Implementation.Context.Factory implementationContextFactory,
3981
                                  TypeValidation typeValidation,
3982
                                  AsmClassReader.Factory classReaderFactory,
3983
                                  AsmClassWriter.Factory classWriterFactory,
3984
                                  TypePool typePool,
3985
                                  TypeDescription originalType,
3986
                                  ClassFileLocator classFileLocator) {
3987
                super(instrumentedType,
1✔
3988
                        classFileVersion,
3989
                        fieldPool,
3990
                        recordComponentPool,
3991
                        auxiliaryTypes,
3992
                        fields,
3993
                        methods,
3994
                        instrumentedMethods,
3995
                        recordComponents,
3996
                        loadedTypeInitializer,
3997
                        typeInitializer,
3998
                        typeAttributeAppender,
3999
                        asmVisitorWrapper,
4000
                        annotationValueFilterFactory,
4001
                        annotationRetention,
4002
                        auxiliaryTypeNamingStrategy,
4003
                        implementationContextFactory,
4004
                        typeValidation,
4005
                        classReaderFactory,
4006
                        classWriterFactory,
4007
                        typePool);
4008
                this.originalType = originalType;
1✔
4009
                this.classFileLocator = classFileLocator;
1✔
4010
            }
1✔
4011

4012
            /**
4013
             * {@inheritDoc}
4014
             */
4015
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
4016
                ContextRegistry contextRegistry = new ContextRegistry();
1✔
4017
                return new RegistryContextClassVisitor(writeTo(ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
4018
                        typeInitializer,
4019
                        contextRegistry,
4020
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
4021
                        asmVisitorWrapper.mergeReader(readerFlags)), contextRegistry);
1✔
4022
            }
4023

4024
            @Override
4025
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
4026
                try {
4027
                    int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS);
1✔
4028
                    int readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
4029
                    byte[] binaryRepresentation = classFileLocator.locate(originalType.getName()).resolve();
1✔
4030
                    dispatcher.dump(instrumentedType, true, binaryRepresentation);
1✔
4031
                    AsmClassReader classReader = classReaderFactory.make(binaryRepresentation);
1✔
4032
                    AsmClassWriter classWriter = classWriterFactory.make(writerFlags, classReader, typePool);
1✔
4033
                    ContextRegistry contextRegistry = new ContextRegistry();
1✔
4034
                    classReader.accept(writeTo(ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
4035
                            typeInitializer,
4036
                            contextRegistry,
4037
                            writerFlags,
4038
                            readerFlags), readerFlags);
4039
                    return new UnresolvedType(classWriter.getBinaryRepresentation(), contextRegistry.getAuxiliaryTypes());
1✔
4040
                } catch (IOException exception) {
×
4041
                    throw new RuntimeException("The class file could not be written", exception);
×
4042
                }
4043
            }
4044

4045
            /**
4046
             * Creates a class visitor which weaves all changes and additions on the fly.
4047
             *
4048
             * @param classVisitor    The class visitor to which this entry is to be written to.
4049
             * @param typeInitializer The type initializer to apply.
4050
             * @param contextRegistry A context registry to register the lazily created implementation context to.
4051
             * @param writerFlags     The writer flags being used.
4052
             * @param readerFlags     The reader flags being used.
4053
             * @return A class visitor which is capable of applying the changes.
4054
             */
4055
            protected abstract ClassVisitor writeTo(ClassVisitor classVisitor,
4056
                                                    TypeInitializer typeInitializer,
4057
                                                    ContextRegistry contextRegistry,
4058
                                                    int writerFlags,
4059
                                                    int readerFlags);
4060

4061
            /**
4062
             * A context class visitor based on a {@link ContextRegistry}.
4063
             */
4064
            protected class RegistryContextClassVisitor extends ContextClassVisitor {
4065

4066
                /**
4067
                 * The context registry to use.
4068
                 */
4069
                private final ContextRegistry contextRegistry;
4070

4071
                /**
4072
                 * Creates a new context class visitor based on a {@link ContextRegistry}.
4073
                 *
4074
                 * @param classVisitor    The class visitor to delegate to.
4075
                 * @param contextRegistry The context registry to use.
4076
                 */
4077
                protected RegistryContextClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry) {
1✔
4078
                    super(classVisitor);
1✔
4079
                    this.contextRegistry = contextRegistry;
1✔
4080
                }
1✔
4081

4082
                @Override
4083
                public List<DynamicType> getAuxiliaryTypes() {
4084
                    return CompoundList.of(auxiliaryTypes, contextRegistry.getAuxiliaryTypes());
1✔
4085
                }
4086

4087
                @Override
4088
                public LoadedTypeInitializer getLoadedTypeInitializer() {
4089
                    return loadedTypeInitializer;
1✔
4090
                }
4091
            }
4092

4093
            /**
4094
             * A context registry allows to extract auxiliary types from a lazily created implementation context.
4095
             */
4096
            protected static class ContextRegistry {
1✔
4097

4098
                /**
4099
                 * The implementation context that is used for creating a class or {@code null} if it was not registered.
4100
                 */
4101
                @UnknownNull
4102
                private Implementation.Context.ExtractableView implementationContext;
4103

4104
                /**
4105
                 * Registers the implementation context.
4106
                 *
4107
                 * @param implementationContext The implementation context.
4108
                 */
4109
                public void setImplementationContext(Implementation.Context.ExtractableView implementationContext) {
4110
                    this.implementationContext = implementationContext;
1✔
4111
                }
1✔
4112

4113
                /**
4114
                 * Returns the auxiliary types that were registered during class creation. This method must only be called after
4115
                 * a class was created.
4116
                 *
4117
                 * @return The auxiliary types that were registered during class creation
4118
                 */
4119
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Lazy value definition is intended.")
4120
                public List<DynamicType> getAuxiliaryTypes() {
4121
                    return implementationContext.getAuxiliaryTypes();
1✔
4122
                }
4123
            }
4124

4125
            /**
4126
             * A default type writer that reprocesses a type completely.
4127
             *
4128
             * @param <V> The best known loaded type for the dynamically created type.
4129
             */
4130
            @HashCodeAndEqualsPlugin.Enhance
4131
            protected static class WithFullProcessing<V> extends ForInlining<V> {
4132

4133
                /**
4134
                 * An empty array to indicate missing frames.
4135
                 */
4136
                private static final Object[] EMPTY = new Object[0];
1✔
4137

4138
                /**
4139
                 * The method registry to use.
4140
                 */
4141
                private final MethodRegistry.Prepared methodRegistry;
4142

4143
                /**
4144
                 * The implementation target factory to use.
4145
                 */
4146
                private final Implementation.Target.Factory implementationTargetFactory;
4147

4148
                /**
4149
                 * The method rebase resolver to use for rebasing methods.
4150
                 */
4151
                private final MethodRebaseResolver methodRebaseResolver;
4152

4153
                /**
4154
                 * Creates a new inlining type writer that fully reprocesses a type.
4155
                 *
4156
                 * @param instrumentedType             The instrumented type to be created.
4157
                 * @param classFileVersion             The class file specified by the user.
4158
                 * @param fieldPool                    The field pool to use.
4159
                 * @param recordComponentPool          The record component pool to use.
4160
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
4161
                 * @param fields                       The instrumented type's declared fields.
4162
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
4163
                 * @param instrumentedMethods          The instrumented methods relevant to this type creation.
4164
                 * @param recordComponents             The instrumented type's record components.
4165
                 * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
4166
                 * @param typeInitializer              The type initializer to include in the created type's type initializer.
4167
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
4168
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
4169
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
4170
                 * @param annotationRetention          The annotation retention to apply.
4171
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
4172
                 * @param implementationContextFactory The implementation context factory to apply.
4173
                 * @param typeValidation               Determines if a type should be explicitly validated.
4174
                 * @param classReaderFactory           The class reader factory to use.
4175
                 * @param classWriterFactory           The class writer factory to use.
4176
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
4177
                 * @param originalType                 The original type's description.
4178
                 * @param classFileLocator             The class file locator for locating the original type's class file.
4179
                 * @param methodRegistry               The method registry to use.
4180
                 * @param implementationTargetFactory  The implementation target factory to use.
4181
                 * @param methodRebaseResolver         The method rebase resolver to use for rebasing methods.
4182
                 */
4183
                protected WithFullProcessing(TypeDescription instrumentedType,
4184
                                             ClassFileVersion classFileVersion,
4185
                                             FieldPool fieldPool,
4186
                                             RecordComponentPool recordComponentPool,
4187
                                             List<? extends DynamicType> auxiliaryTypes,
4188
                                             FieldList<FieldDescription.InDefinedShape> fields,
4189
                                             MethodList<?> methods, MethodList<?> instrumentedMethods,
4190
                                             RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
4191
                                             LoadedTypeInitializer loadedTypeInitializer,
4192
                                             TypeInitializer typeInitializer,
4193
                                             TypeAttributeAppender typeAttributeAppender,
4194
                                             AsmVisitorWrapper asmVisitorWrapper,
4195
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
4196
                                             AnnotationRetention annotationRetention,
4197
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
4198
                                             Implementation.Context.Factory implementationContextFactory,
4199
                                             TypeValidation typeValidation,
4200
                                             AsmClassReader.Factory classReaderFactory,
4201
                                             AsmClassWriter.Factory classWriterFactory,
4202
                                             TypePool typePool,
4203
                                             TypeDescription originalType,
4204
                                             ClassFileLocator classFileLocator,
4205
                                             MethodRegistry.Prepared methodRegistry,
4206
                                             Implementation.Target.Factory implementationTargetFactory,
4207
                                             MethodRebaseResolver methodRebaseResolver) {
4208
                    super(instrumentedType,
1✔
4209
                            classFileVersion,
4210
                            fieldPool,
4211
                            recordComponentPool,
4212
                            auxiliaryTypes,
4213
                            fields,
4214
                            methods,
4215
                            instrumentedMethods,
4216
                            recordComponents,
4217
                            loadedTypeInitializer,
4218
                            typeInitializer,
4219
                            typeAttributeAppender,
4220
                            asmVisitorWrapper,
4221
                            annotationValueFilterFactory,
4222
                            annotationRetention,
4223
                            auxiliaryTypeNamingStrategy,
4224
                            implementationContextFactory,
4225
                            typeValidation,
4226
                            classReaderFactory,
4227
                            classWriterFactory,
4228
                            typePool,
4229
                            originalType,
4230
                            classFileLocator);
4231
                    this.methodRegistry = methodRegistry;
1✔
4232
                    this.implementationTargetFactory = implementationTargetFactory;
1✔
4233
                    this.methodRebaseResolver = methodRebaseResolver;
1✔
4234
                }
1✔
4235

4236
                /**
4237
                 * {@inheritDoc}
4238
                 */
4239
                protected ClassVisitor writeTo(ClassVisitor classVisitor, TypeInitializer typeInitializer, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
4240
                    classVisitor = new RedefinitionClassVisitor(classVisitor, typeInitializer, contextRegistry, writerFlags, readerFlags);
1✔
4241
                    return originalType.getName().equals(instrumentedType.getName())
1✔
4242
                            ? classVisitor
4243
                            : new OpenedClassRemapper(classVisitor, new SimpleRemapper(originalType.getInternalName(), instrumentedType.getInternalName()));
1✔
4244
                }
4245

4246
                /**
4247
                 * A {@link ClassRemapper} that uses the Byte Buddy-defined API version.
4248
                 */
4249
                protected static class OpenedClassRemapper extends ClassRemapper {
4250

4251
                    /**
4252
                     * Creates a new opened class remapper.
4253
                     *
4254
                     * @param classVisitor The class visitor to wrap
4255
                     * @param remapper     The remapper to apply.
4256
                     */
4257
                    protected OpenedClassRemapper(ClassVisitor classVisitor, Remapper remapper) {
4258
                        super(OpenedClassReader.ASM_API, classVisitor, remapper);
1✔
4259
                    }
1✔
4260
                }
4261

4262
                /**
4263
                 * An initialization handler is responsible for handling the creation of the type initializer.
4264
                 */
4265
                protected interface InitializationHandler {
4266

4267
                    /**
4268
                     * Invoked upon completion of writing the instrumented type.
4269
                     *
4270
                     * @param classVisitor          The class visitor to write any methods to.
4271
                     * @param implementationContext The implementation context to use.
4272
                     */
4273
                    void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext);
4274

4275
                    /**
4276
                     * An initialization handler that creates a new type initializer.
4277
                     */
4278
                    class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4279

4280
                        /**
4281
                         * Creates a new creating initialization handler.
4282
                         *
4283
                         * @param instrumentedType             The instrumented type.
4284
                         * @param methodPool                   The method pool to use.
4285
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4286
                         */
4287
                        protected Creating(TypeDescription instrumentedType,
4288
                                           MethodPool methodPool,
4289
                                           AnnotationValueFilter.Factory annotationValueFilterFactory) {
4290
                            super(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
4291
                        }
1✔
4292

4293
                        /**
4294
                         * {@inheritDoc}
4295
                         */
4296
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4297
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4298
                        }
1✔
4299
                    }
4300

4301
                    /**
4302
                     * An initialization handler that appends code to a previously visited type initializer.
4303
                     */
4304
                    abstract class Appending extends MethodVisitor implements InitializationHandler, TypeInitializer.Drain {
4305

4306
                        /**
4307
                         * The instrumented type.
4308
                         */
4309
                        protected final TypeDescription instrumentedType;
4310

4311
                        /**
4312
                         * The method pool record for the type initializer.
4313
                         */
4314
                        protected final MethodPool.Record record;
4315

4316
                        /**
4317
                         * The used annotation value filter factory.
4318
                         */
4319
                        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4320

4321
                        /**
4322
                         * The frame writer to use.
4323
                         */
4324
                        protected final FrameWriter frameWriter;
4325

4326
                        /**
4327
                         * The currently recorded stack size.
4328
                         */
4329
                        protected int stackSize;
4330

4331
                        /**
4332
                         * The currently recorded local variable length.
4333
                         */
4334
                        protected int localVariableLength;
4335

4336
                        /**
4337
                         * Creates a new appending initialization handler.
4338
                         *
4339
                         * @param methodVisitor                The underlying method visitor.
4340
                         * @param instrumentedType             The instrumented type.
4341
                         * @param record                       The method pool record for the type initializer.
4342
                         * @param annotationValueFilterFactory The used annotation value filter factory.
4343
                         * @param requireFrames                {@code true} if the visitor is required to add frames.
4344
                         * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4345
                         */
4346
                        protected Appending(MethodVisitor methodVisitor,
4347
                                            TypeDescription instrumentedType,
4348
                                            MethodPool.Record record,
4349
                                            AnnotationValueFilter.Factory annotationValueFilterFactory,
4350
                                            boolean requireFrames,
4351
                                            boolean expandFrames) {
4352
                            super(OpenedClassReader.ASM_API, methodVisitor);
1✔
4353
                            this.instrumentedType = instrumentedType;
1✔
4354
                            this.record = record;
1✔
4355
                            this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
4356
                            if (!requireFrames) {
1✔
4357
                                frameWriter = FrameWriter.NoOp.INSTANCE;
1✔
4358
                            } else if (expandFrames) {
1✔
4359
                                frameWriter = FrameWriter.Expanding.INSTANCE;
×
4360
                            } else {
4361
                                frameWriter = new FrameWriter.Active();
1✔
4362
                            }
4363
                        }
1✔
4364

4365
                        /**
4366
                         * Resolves an initialization handler.
4367
                         *
4368
                         * @param enabled                      {@code true} if the implementation context is enabled, i.e. any {@link TypeInitializer} might be active.
4369
                         * @param methodVisitor                The delegation method visitor.
4370
                         * @param instrumentedType             The instrumented type.
4371
                         * @param methodPool                   The method pool to use.
4372
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4373
                         * @param requireFrames                {@code true} if frames must be computed.
4374
                         * @param expandFrames                 {@code true} if frames must be expanded.
4375
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4376
                         */
4377
                        protected static InitializationHandler of(boolean enabled,
4378
                                                                  MethodVisitor methodVisitor,
4379
                                                                  TypeDescription instrumentedType,
4380
                                                                  MethodPool methodPool,
4381
                                                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
4382
                                                                  boolean requireFrames,
4383
                                                                  boolean expandFrames) {
4384
                            return enabled
1✔
4385
                                    ? withDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames)
1✔
4386
                                    : withoutDrain(methodVisitor, instrumentedType, methodPool, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4387
                        }
4388

4389
                        /**
4390
                         * Resolves an initialization handler with a drain.
4391
                         *
4392
                         * @param methodVisitor                The delegation method visitor.
4393
                         * @param instrumentedType             The instrumented type.
4394
                         * @param methodPool                   The method pool to use.
4395
                         * @param annotationValueFilterFactory The annotation value filter factory to use.
4396
                         * @param requireFrames                {@code true} if frames must be computed.
4397
                         * @param expandFrames                 {@code true} if frames must be expanded.
4398
                         * @return An initialization handler which is also guaranteed to be a {@link MethodVisitor}.
4399
                         */
4400
                        private static WithDrain withDrain(MethodVisitor methodVisitor,
4401
                                                           TypeDescription instrumentedType,
4402
                                                           MethodPool methodPool,
4403
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4404
                                                           boolean requireFrames,
4405
                                                           boolean expandFrames) {
4406
                            MethodPool.Record record = methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4407
                            return record.getSort().isImplemented()
1✔
4408
                                    ? new WithDrain.WithActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames)
4409
                                    : new WithDrain.WithoutActiveRecord(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
4410
                        }
4411

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

4435
                        @Override
4436
                        public void visitCode() {
4437
                            record.applyAttributes(mv, annotationValueFilterFactory);
1✔
4438
                            super.visitCode();
1✔
4439
                            onStart();
1✔
4440
                        }
1✔
4441

4442
                        /**
4443
                         * Invoked after the user code was visited.
4444
                         */
4445
                        protected abstract void onStart();
4446

4447
                        @Override
4448
                        public void visitFrame(int type, int localVariableLength, @MaybeNull Object[] localVariable, int stackSize, @MaybeNull Object[] stack) {
4449
                            super.visitFrame(type, localVariableLength, localVariable, stackSize, stack);
1✔
4450
                            frameWriter.onFrame(type, localVariableLength);
1✔
4451
                        }
1✔
4452

4453
                        @Override
4454
                        public void visitMaxs(int stackSize, int localVariableLength) {
4455
                            this.stackSize = stackSize;
1✔
4456
                            this.localVariableLength = localVariableLength;
1✔
4457
                        }
1✔
4458

4459
                        @Override
4460
                        public abstract void visitEnd();
4461

4462
                        /**
4463
                         * {@inheritDoc}
4464
                         */
4465
                        public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
4466
                            ByteCodeAppender.Size size = typeInitializer.apply(mv, implementationContext, new MethodDescription.Latent.TypeInitializer(instrumentedType));
1✔
4467
                            stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4468
                            localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4469
                            onComplete(implementationContext);
1✔
4470
                        }
1✔
4471

4472
                        /**
4473
                         * Invoked upon completion of writing the type initializer.
4474
                         *
4475
                         * @param implementationContext The implementation context to use.
4476
                         */
4477
                        protected abstract void onComplete(Implementation.Context implementationContext);
4478

4479
                        /**
4480
                         * {@inheritDoc}
4481
                         */
4482
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4483
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4484
                            mv.visitMaxs(stackSize, localVariableLength);
1✔
4485
                            mv.visitEnd();
1✔
4486
                        }
1✔
4487

4488
                        /**
4489
                         * A frame writer is responsible for adding empty frames on jump instructions.
4490
                         */
4491
                        protected interface FrameWriter {
4492

4493
                            /**
4494
                             * An empty array.
4495
                             */
4496
                            Object[] EMPTY = new Object[0];
1✔
4497

4498
                            /**
4499
                             * Informs this frame writer of an observed frame.
4500
                             *
4501
                             * @param type                The frame type.
4502
                             * @param localVariableLength The length of the local variables array.
4503
                             */
4504
                            void onFrame(int type, int localVariableLength);
4505

4506
                            /**
4507
                             * Emits an empty frame.
4508
                             *
4509
                             * @param methodVisitor The method visitor to write the frame to.
4510
                             */
4511
                            void emitFrame(MethodVisitor methodVisitor);
4512

4513
                            /**
4514
                             * A non-operational frame writer.
4515
                             */
4516
                            enum NoOp implements FrameWriter {
1✔
4517

4518
                                /**
4519
                                 * The singleton instance.
4520
                                 */
4521
                                INSTANCE;
1✔
4522

4523
                                /**
4524
                                 * {@inheritDoc}
4525
                                 */
4526
                                public void onFrame(int type, int localVariableLength) {
4527
                                    /* do nothing */
4528
                                }
1✔
4529

4530
                                /**
4531
                                 * {@inheritDoc}
4532
                                 */
4533
                                public void emitFrame(MethodVisitor methodVisitor) {
4534
                                    /* do nothing */
4535
                                }
1✔
4536
                            }
4537

4538
                            /**
4539
                             * A frame writer that creates an expanded frame.
4540
                             */
4541
                            enum Expanding implements FrameWriter {
1✔
4542

4543
                                /**
4544
                                 * The singleton instance.
4545
                                 */
4546
                                INSTANCE;
1✔
4547

4548
                                /**
4549
                                 * {@inheritDoc}
4550
                                 */
4551
                                public void onFrame(int type, int localVariableLength) {
4552
                                    /* do nothing */
4553
                                }
1✔
4554

4555
                                /**
4556
                                 * {@inheritDoc}
4557
                                 */
4558
                                public void emitFrame(MethodVisitor methodVisitor) {
4559
                                    methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4560
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4561
                                }
1✔
4562
                            }
4563

4564
                            /**
4565
                             * An active frame writer that creates the most efficient frame.
4566
                             */
4567
                            class Active implements FrameWriter {
1✔
4568

4569
                                /**
4570
                                 * The current length of the current local variable array.
4571
                                 */
4572
                                private int currentLocalVariableLength;
4573

4574
                                /**
4575
                                 * {@inheritDoc}
4576
                                 */
4577
                                public void onFrame(int type, int localVariableLength) {
4578
                                    switch (type) {
1✔
4579
                                        case Opcodes.F_SAME:
4580
                                        case Opcodes.F_SAME1:
4581
                                            break;
1✔
4582
                                        case Opcodes.F_APPEND:
4583
                                            currentLocalVariableLength += localVariableLength;
1✔
4584
                                            break;
1✔
4585
                                        case Opcodes.F_CHOP:
4586
                                            currentLocalVariableLength -= localVariableLength;
1✔
4587
                                            break;
1✔
4588
                                        case Opcodes.F_NEW:
4589
                                        case Opcodes.F_FULL:
4590
                                            currentLocalVariableLength = localVariableLength;
1✔
4591
                                            break;
1✔
4592
                                        default:
4593
                                            throw new IllegalStateException("Unexpected frame type: " + type);
1✔
4594
                                    }
4595
                                }
1✔
4596

4597
                                /**
4598
                                 * {@inheritDoc}
4599
                                 */
4600
                                public void emitFrame(MethodVisitor methodVisitor) {
4601
                                    if (currentLocalVariableLength == 0) {
1✔
4602
                                        methodVisitor.visitFrame(Opcodes.F_SAME, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4603
                                    } else if (currentLocalVariableLength > 3) {
1✔
4604
                                        methodVisitor.visitFrame(Opcodes.F_FULL, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4605
                                    } else {
4606
                                        methodVisitor.visitFrame(Opcodes.F_CHOP, currentLocalVariableLength, EMPTY, EMPTY.length, EMPTY);
1✔
4607
                                    }
4608
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4609
                                    currentLocalVariableLength = 0;
1✔
4610
                                }
1✔
4611
                            }
4612
                        }
4613

4614
                        /**
4615
                         * An initialization handler that appends code to a previously visited type initializer without allowing active
4616
                         * {@link TypeInitializer} registrations.
4617
                         */
4618
                        protected abstract static class WithoutDrain extends Appending {
4619

4620
                            /**
4621
                             * Creates a new appending initialization handler without a drain.
4622
                             *
4623
                             * @param methodVisitor                The underlying method visitor.
4624
                             * @param instrumentedType             The instrumented type.
4625
                             * @param record                       The method pool record for the type initializer.
4626
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4627
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4628
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4629
                             */
4630
                            protected WithoutDrain(MethodVisitor methodVisitor,
4631
                                                   TypeDescription instrumentedType,
4632
                                                   MethodPool.Record record,
4633
                                                   AnnotationValueFilter.Factory annotationValueFilterFactory,
4634
                                                   boolean requireFrames,
4635
                                                   boolean expandFrames) {
4636
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4637
                            }
1✔
4638

4639
                            @Override
4640
                            protected void onStart() {
4641
                                /* do nothing */
4642
                            }
1✔
4643

4644
                            @Override
4645
                            public void visitEnd() {
4646
                                /* do nothing */
4647
                            }
1✔
4648

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

4655
                                /**
4656
                                 * Creates a new appending initialization handler without a drain and without an active record.
4657
                                 *
4658
                                 * @param methodVisitor                The underlying method visitor.
4659
                                 * @param instrumentedType             The instrumented type.
4660
                                 * @param record                       The method pool record for the type initializer.
4661
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4662
                                 */
4663
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4664
                                                              TypeDescription instrumentedType,
4665
                                                              MethodPool.Record record,
4666
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory) {
4667
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, false, false);
1✔
4668
                                }
1✔
4669

4670
                                @Override
4671
                                protected void onComplete(Implementation.Context implementationContext) {
4672
                                    /* do nothing */
4673
                                }
1✔
4674
                            }
4675

4676
                            /**
4677
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4678
                             * {@link TypeInitializer} registrations and with an active record.
4679
                             */
4680
                            protected static class WithActiveRecord extends WithoutDrain {
4681

4682
                                /**
4683
                                 * The label that indicates the beginning of the active record.
4684
                                 */
4685
                                private final Label label;
4686

4687
                                /**
4688
                                 * Creates a new appending initialization handler without a drain and with an active record.
4689
                                 *
4690
                                 * @param methodVisitor                The underlying method visitor.
4691
                                 * @param instrumentedType             The instrumented type.
4692
                                 * @param record                       The method pool record for the type initializer.
4693
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4694
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4695
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4696
                                 */
4697
                                protected WithActiveRecord(MethodVisitor methodVisitor,
4698
                                                           TypeDescription instrumentedType,
4699
                                                           MethodPool.Record record,
4700
                                                           AnnotationValueFilter.Factory annotationValueFilterFactory,
4701
                                                           boolean requireFrames,
4702
                                                           boolean expandFrames) {
4703
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4704
                                    label = new Label();
1✔
4705
                                }
1✔
4706

4707
                                @Override
4708
                                public void visitInsn(int opcode) {
4709
                                    if (opcode == Opcodes.RETURN) {
1✔
4710
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4711
                                    } else {
4712
                                        super.visitInsn(opcode);
1✔
4713
                                    }
4714
                                }
1✔
4715

4716
                                @Override
4717
                                protected void onComplete(Implementation.Context implementationContext) {
4718
                                    mv.visitLabel(label);
1✔
4719
                                    frameWriter.emitFrame(mv);
1✔
4720
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4721
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4722
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4723
                                }
1✔
4724

4725
                            }
4726
                        }
4727

4728
                        /**
4729
                         * An initialization handler that appends code to a previously visited type initializer with allowing active
4730
                         * {@link TypeInitializer} registrations.
4731
                         */
4732
                        protected abstract static class WithDrain extends Appending {
4733

4734
                            /**
4735
                             * A label marking the beginning of the appended code.
4736
                             */
4737
                            protected final Label appended;
4738

4739
                            /**
4740
                             * A label marking the beginning og the original type initializer's code.
4741
                             */
4742
                            protected final Label original;
4743

4744
                            /**
4745
                             * Creates a new appending initialization handler with a drain.
4746
                             *
4747
                             * @param methodVisitor                The underlying method visitor.
4748
                             * @param instrumentedType             The instrumented type.
4749
                             * @param record                       The method pool record for the type initializer.
4750
                             * @param annotationValueFilterFactory The used annotation value filter factory.
4751
                             * @param requireFrames                {@code true} if the visitor is required to add frames.
4752
                             * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4753
                             */
4754
                            protected WithDrain(MethodVisitor methodVisitor,
4755
                                                TypeDescription instrumentedType,
4756
                                                MethodPool.Record record,
4757
                                                AnnotationValueFilter.Factory annotationValueFilterFactory,
4758
                                                boolean requireFrames,
4759
                                                boolean expandFrames) {
4760
                                super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4761
                                appended = new Label();
1✔
4762
                                original = new Label();
1✔
4763
                            }
1✔
4764

4765
                            @Override
4766
                            protected void onStart() {
4767
                                mv.visitJumpInsn(Opcodes.GOTO, appended);
1✔
4768
                                mv.visitLabel(original);
1✔
4769
                                frameWriter.emitFrame(mv);
1✔
4770
                            }
1✔
4771

4772
                            @Override
4773
                            public void visitEnd() {
4774
                                mv.visitLabel(appended);
1✔
4775
                                frameWriter.emitFrame(mv);
1✔
4776
                            }
1✔
4777

4778
                            @Override
4779
                            protected void onComplete(Implementation.Context implementationContext) {
4780
                                mv.visitJumpInsn(Opcodes.GOTO, original);
1✔
4781
                                onAfterComplete(implementationContext);
1✔
4782
                            }
1✔
4783

4784
                            /**
4785
                             * Invoked after completion of writing the type initializer.
4786
                             *
4787
                             * @param implementationContext The implementation context to use.
4788
                             */
4789
                            protected abstract void onAfterComplete(Implementation.Context implementationContext);
4790

4791
                            /**
4792
                             * A code appending initialization handler with a drain that does not apply an explicit record.
4793
                             */
4794
                            protected static class WithoutActiveRecord extends WithDrain {
4795

4796
                                /**
4797
                                 * Creates a new appending initialization handler with a drain and without an active record.
4798
                                 *
4799
                                 * @param methodVisitor                The underlying method visitor.
4800
                                 * @param instrumentedType             The instrumented type.
4801
                                 * @param record                       The method pool record for the type initializer.
4802
                                 * @param annotationValueFilterFactory The used annotation value filter factory.
4803
                                 * @param requireFrames                {@code true} if the visitor is required to add frames.
4804
                                 * @param expandFrames                 {@code true} if the visitor is required to expand any added frame.
4805
                                 */
4806
                                protected WithoutActiveRecord(MethodVisitor methodVisitor,
4807
                                                              TypeDescription instrumentedType,
4808
                                                              MethodPool.Record record,
4809
                                                              AnnotationValueFilter.Factory annotationValueFilterFactory,
4810
                                                              boolean requireFrames,
4811
                                                              boolean expandFrames) {
4812
                                    super(methodVisitor, instrumentedType, record, annotationValueFilterFactory, requireFrames, expandFrames);
1✔
4813
                                }
1✔
4814

4815
                                @Override
4816
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4817
                                    /* do nothing */
4818
                                }
1✔
4819
                            }
4820

4821
                            /**
4822
                             * A code appending initialization handler with a drain that applies an explicit record.
4823
                             */
4824
                            protected static class WithActiveRecord extends WithDrain {
4825

4826
                                /**
4827
                                 * A label indicating the beginning of the record's code.
4828
                                 */
4829
                                private final Label label;
4830

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

4851
                                @Override
4852
                                public void visitInsn(int opcode) {
4853
                                    if (opcode == Opcodes.RETURN) {
1✔
4854
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4855
                                    } else {
4856
                                        super.visitInsn(opcode);
1✔
4857
                                    }
4858
                                }
1✔
4859

4860
                                @Override
4861
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4862
                                    mv.visitLabel(label);
1✔
4863
                                    frameWriter.emitFrame(mv);
1✔
4864
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4865
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4866
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4867
                                }
1✔
4868
                            }
4869
                        }
4870
                    }
4871
                }
4872

4873
                /**
4874
                 * A class visitor which is capable of applying a redefinition of an existing class file.
4875
                 */
4876
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
4877
                protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
4878

4879
                    /**
4880
                     * The type initializer to apply.
4881
                     */
4882
                    private final TypeInitializer typeInitializer;
4883

4884
                    /**
4885
                     * A context registry to register the lazily created implementation context to.
4886
                     */
4887
                    private final ContextRegistry contextRegistry;
4888

4889
                    /**
4890
                     * The writer flags being used.
4891
                     */
4892
                    private final int writerFlags;
4893

4894
                    /**
4895
                     * The reader flags being used.
4896
                     */
4897
                    private final int readerFlags;
4898

4899
                    /**
4900
                     * A mapping of fields to write by their unique signature.
4901
                     */
4902
                    private final LinkedHashMap<SignatureKey, FieldDescription> declarableFields;
4903

4904
                    /**
4905
                     * A mapping of methods to write by their unique signature.
4906
                     */
4907
                    private final LinkedHashMap<SignatureKey, MethodDescription> declarableMethods;
4908

4909
                    /**
4910
                     * A mapping of record components to write by their names.
4911
                     */
4912
                    private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
4913

4914
                    /**
4915
                     * 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.
4916
                     */
4917
                    private final Set<String> nestMembers;
4918

4919
                    /**
4920
                     * A mapping of the internal names of all declared types to their description.
4921
                     */
4922
                    private final LinkedHashMap<String, TypeDescription> declaredTypes;
4923

4924
                    /**
4925
                     * A list of internal names of permitted subclasses to include.
4926
                     */
4927
                    @MaybeNull
4928
                    private final Set<String> permittedSubclasses;
4929

4930
                    /**
4931
                     * The method pool to use or {@code null} if the pool was not yet initialized.
4932
                     */
4933
                    @UnknownNull
4934
                    private MethodPool methodPool;
4935

4936
                    /**
4937
                     * The initialization handler to use or {@code null} if the handler was not yet initialized.
4938
                     */
4939
                    @UnknownNull
4940
                    private InitializationHandler initializationHandler;
4941

4942
                    /**
4943
                     * The implementation context for this class creation or {@code null} if it was not yet created.
4944
                     */
4945
                    @UnknownNull
4946
                    private Implementation.Context.ExtractableView implementationContext;
4947

4948
                    /**
4949
                     * {@code true} if the modifiers for deprecation should be retained.
4950
                     */
4951
                    private boolean retainDeprecationModifiers;
4952

4953
                    /**
4954
                     * A set of keys for fields that were previosuly visited.
4955
                     */
4956
                    private final Set<SignatureKey> fieldKeys = new HashSet<SignatureKey>();
1✔
4957

4958
                    /**
4959
                     * A set of keys for methods that were previosuly visited.
4960
                     */
4961
                    private final Set<SignatureKey> methodsKeys = new HashSet<SignatureKey>();
1✔
4962

4963
                    /**
4964
                     * Creates a class visitor which is capable of redefining an existent class on the fly.
4965
                     *
4966
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
4967
                     * @param typeInitializer The type initializer to apply.
4968
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
4969
                     * @param writerFlags     The writer flags being used.
4970
                     * @param readerFlags     The reader flags being used.
4971
                     */
4972
                    protected RedefinitionClassVisitor(ClassVisitor classVisitor,
4973
                                                       TypeInitializer typeInitializer,
4974
                                                       ContextRegistry contextRegistry,
4975
                                                       int writerFlags,
4976
                                                       int readerFlags) {
1✔
4977
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
4978
                        this.typeInitializer = typeInitializer;
1✔
4979
                        this.contextRegistry = contextRegistry;
1✔
4980
                        this.writerFlags = writerFlags;
1✔
4981
                        this.readerFlags = readerFlags;
1✔
4982
                        declarableFields = new LinkedHashMap<SignatureKey, FieldDescription>((int) Math.ceil(fields.size() / 0.75));
1✔
4983
                        for (FieldDescription fieldDescription : fields) {
1✔
4984
                            declarableFields.put(new SignatureKey(fieldDescription.getInternalName(), fieldDescription.getDescriptor()), fieldDescription);
1✔
4985
                        }
1✔
4986
                        declarableMethods = new LinkedHashMap<SignatureKey, MethodDescription>((int) Math.ceil(instrumentedMethods.size() / 0.75));
1✔
4987
                        for (MethodDescription methodDescription : instrumentedMethods) {
1✔
4988
                            declarableMethods.put(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()), methodDescription);
1✔
4989
                        }
1✔
4990
                        declarableRecordComponents = new LinkedHashMap<String, RecordComponentDescription>((int) Math.ceil(recordComponents.size() / 0.75));
1✔
4991
                        for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
4992
                            declarableRecordComponents.put(recordComponentDescription.getActualName(), recordComponentDescription);
×
4993
                        }
×
4994
                        if (instrumentedType.isNestHost()) {
1✔
4995
                            nestMembers = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getNestMembers().size() / 0.75));
1✔
4996
                            for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
4997
                                nestMembers.add(typeDescription.getInternalName());
×
4998
                            }
1✔
4999
                        } else {
5000
                            nestMembers = Collections.emptySet();
×
5001
                        }
5002
                        declaredTypes = new LinkedHashMap<String, TypeDescription>((int) Math.ceil(instrumentedType.getDeclaredTypes().size() / 0.75));
1✔
5003
                        for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
5004
                            declaredTypes.put(typeDescription.getInternalName(), typeDescription);
1✔
5005
                        }
1✔
5006
                        if (instrumentedType.isSealed()) {
1✔
5007
                            permittedSubclasses = new LinkedHashSet<String>((int) Math.ceil(instrumentedType.getPermittedSubtypes().size() / 0.75));
×
5008
                            for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
×
5009
                                permittedSubclasses.add(typeDescription.getInternalName());
×
5010
                            }
×
5011
                        } else {
5012
                            permittedSubclasses = null;
1✔
5013
                        }
5014
                    }
1✔
5015

5016
                    @Override
5017
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
5018
                    public void visit(int classFileVersionNumber,
5019
                                      int modifiers,
5020
                                      String internalName,
5021
                                      String genericSignature,
5022
                                      String superClassInternalName,
5023
                                      String[] interfaceTypeInternalName) {
5024
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5025
                        methodPool = methodRegistry.compile(implementationTargetFactory, classFileVersion);
1✔
5026
                        initializationHandler = new InitializationHandler.Creating(instrumentedType, methodPool, annotationValueFilterFactory);
1✔
5027
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5028
                                auxiliaryTypeNamingStrategy,
5029
                                typeInitializer,
5030
                                classFileVersion,
5031
                                WithFullProcessing.this.classFileVersion,
5032
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5033
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5034
                                        : Implementation.Context.FrameGeneration.DISABLED);
5035
                        retainDeprecationModifiers = classFileVersion.isLessThan(ClassFileVersion.JAVA_V5);
1✔
5036
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5037
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5038
                                cv,
5039
                                implementationContext,
5040
                                typePool,
5041
                                fields,
5042
                                methods,
5043
                                writerFlags,
5044
                                readerFlags);
5045
                        cv.visit(classFileVersionNumber,
1✔
5046
                                instrumentedType.getActualModifiers((modifiers & Opcodes.ACC_SUPER) != 0 && !instrumentedType.isInterface())
1✔
5047
                                        | resolveDeprecationModifiers(modifiers)
1✔
5048
                                        // Anonymous types might not preserve their class file's final modifier via their inner class modifier.
5049
                                        | (((modifiers & Opcodes.ACC_FINAL) != 0 && instrumentedType.isAnonymousType()) ? Opcodes.ACC_FINAL : 0),
1✔
5050
                                instrumentedType.getInternalName(),
1✔
5051
                                TypeDescription.AbstractBase.RAW_TYPES
5052
                                        ? genericSignature
5053
                                        : instrumentedType.getGenericSignature(),
1✔
5054
                                instrumentedType.getSuperClass() == null
1✔
5055
                                        ? (instrumentedType.isInterface() ? TypeDescription.ForLoadedType.of(Object.class).getInternalName() : NO_REFERENCE)
1✔
5056
                                        : instrumentedType.getSuperClass().asErasure().getInternalName(),
1✔
5057
                                instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
5058
                    }
1✔
5059

5060
                    @Override
5061
                    protected void onVisitNestHost(String nestHost) {
5062
                        onNestHost();
×
5063
                    }
×
5064

5065
                    @Override
5066
                    protected void onNestHost() {
5067
                        if (!instrumentedType.isNestHost()) {
1✔
5068
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5069
                        }
5070
                    }
1✔
5071

5072
                    @Override
5073
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5074
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
5075
                            cv.visitPermittedSubclass(permittedSubclass);
×
5076
                        }
5077
                    }
×
5078

5079
                    @Override
5080
                    protected void onVisitOuterClass(String owner, @MaybeNull String name, @MaybeNull String descriptor) {
5081
                        try { // The Groovy compiler often gets this attribute wrong such that this safety just retains it.
5082
                            onOuterType();
×
5083
                        } catch (Throwable ignored) {
×
5084
                            cv.visitOuterClass(owner, name, descriptor);
×
5085
                        }
×
5086
                    }
×
5087

5088
                    @Override
5089
                    @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH", justification = "Relying on correlated type properties.")
5090
                    protected void onOuterType() {
5091
                        MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
5092
                        if (enclosingMethod != null) {
1✔
5093
                            cv.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
5094
                                    enclosingMethod.getInternalName(),
1✔
5095
                                    enclosingMethod.getDescriptor());
1✔
5096
                        } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
5097
                            cv.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
5098
                        }
5099
                    }
1✔
5100

5101
                    @Override
5102
                    protected void onAfterAttributes() {
5103
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5104
                    }
1✔
5105

5106
                    @Override
5107
                    @MaybeNull
5108
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5109
                        return annotationRetention.isEnabled()
1✔
5110
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
1✔
5111
                                : IGNORE_ANNOTATION;
×
5112
                    }
5113

5114
                    @Override
5115
                    @MaybeNull
5116
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5117
                        return annotationRetention.isEnabled()
1✔
5118
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5119
                                : IGNORE_ANNOTATION;
1✔
5120
                    }
5121

5122
                    @Override
5123
                    @MaybeNull
5124
                    protected RecordComponentVisitor onVisitRecordComponent(String name, String descriptor, @MaybeNull String genericSignature) {
5125
                        RecordComponentDescription recordComponentDescription = declarableRecordComponents.remove(name);
×
5126
                        if (recordComponentDescription != null) {
×
5127
                            RecordComponentPool.Record record = recordComponentPool.target(recordComponentDescription);
×
5128
                            if (!record.isImplicit()) {
×
5129
                                return redefine(record, genericSignature);
×
5130
                            }
5131
                        }
5132
                        return cv.visitRecordComponent(name, descriptor, genericSignature);
×
5133
                    }
5134

5135
                    /**
5136
                     * Redefines a record component using the given explicit record component pool record.
5137
                     *
5138
                     * @param record           The record component pool record to apply during visitation of the existing record.
5139
                     * @param genericSignature The record component's original generic signature which can be {@code null}.
5140
                     * @return A record component visitor for visiting the existing record component definition.
5141
                     */
5142
                    @MaybeNull
5143
                    protected RecordComponentVisitor redefine(RecordComponentPool.Record record, @MaybeNull String genericSignature) {
5144
                        RecordComponentDescription recordComponentDescription = record.getRecordComponent();
×
5145
                        RecordComponentVisitor recordComponentVisitor = cv.visitRecordComponent(recordComponentDescription.getActualName(),
×
5146
                                recordComponentDescription.getDescriptor(),
×
5147
                                TypeDescription.AbstractBase.RAW_TYPES
5148
                                        ? genericSignature
5149
                                        : recordComponentDescription.getGenericSignature());
×
5150
                        return recordComponentVisitor == null
×
5151
                                ? IGNORE_RECORD_COMPONENT
×
5152
                                : new AttributeObtainingRecordComponentVisitor(recordComponentVisitor, record);
5153
                    }
5154

5155
                    @Override
5156
                    @MaybeNull
5157
                    protected FieldVisitor onVisitField(int modifiers,
5158
                                                        String internalName,
5159
                                                        String descriptor,
5160
                                                        @MaybeNull String genericSignature,
5161
                                                        @MaybeNull Object value) {
5162
                        SignatureKey key = new SignatureKey(internalName, descriptor);
1✔
5163
                        fieldKeys.add(key);
1✔
5164
                        FieldDescription fieldDescription = declarableFields.remove(key);
1✔
5165
                        if (fieldDescription != null) {
1✔
5166
                            FieldPool.Record record = fieldPool.target(fieldDescription);
1✔
5167
                            if (!record.isImplicit()) {
1✔
5168
                                return redefine(record, value, modifiers, genericSignature);
1✔
5169
                            }
5170
                        }
5171
                        return cv.visitField(modifiers, internalName, descriptor, genericSignature, value);
1✔
5172
                    }
5173

5174
                    /**
5175
                     * Redefines a field using the given explicit field pool record and default value.
5176
                     *
5177
                     * @param record           The field pool value to apply during visitation of the existing field.
5178
                     * @param value            The default value to write onto the field which might be {@code null}.
5179
                     * @param modifiers        The original modifiers of the transformed field.
5180
                     * @param genericSignature The field's original generic signature which can be {@code null}.
5181
                     * @return A field visitor for visiting the existing field definition.
5182
                     */
5183
                    @MaybeNull
5184
                    protected FieldVisitor redefine(FieldPool.Record record, @MaybeNull Object value, int modifiers, @MaybeNull String genericSignature) {
5185
                        FieldDescription instrumentedField = record.getField();
1✔
5186
                        FieldVisitor fieldVisitor = cv.visitField(instrumentedField.getActualModifiers() | resolveDeprecationModifiers(modifiers),
1✔
5187
                                instrumentedField.getInternalName(),
1✔
5188
                                instrumentedField.getDescriptor(),
1✔
5189
                                TypeDescription.AbstractBase.RAW_TYPES
5190
                                        ? genericSignature
5191
                                        : instrumentedField.getGenericSignature(),
1✔
5192
                                record.resolveDefault(value));
1✔
5193
                        return fieldVisitor == null
1✔
5194
                                ? IGNORE_FIELD
1✔
5195
                                : new AttributeObtainingFieldVisitor(fieldVisitor, record);
5196
                    }
5197

5198
                    @Override
5199
                    @MaybeNull
5200
                    protected MethodVisitor onVisitMethod(int modifiers,
5201
                                                          String internalName,
5202
                                                          String descriptor,
5203
                                                          @MaybeNull String genericSignature,
5204
                                                          @MaybeNull String[] exceptionName) {
5205
                        if (internalName.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) {
1✔
5206
                            MethodVisitor methodVisitor = cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName);
1✔
5207
                            return methodVisitor == null
1✔
5208
                                    ? IGNORE_METHOD
1✔
5209
                                    : (MethodVisitor) (initializationHandler = InitializationHandler.Appending.of(implementationContext.isEnabled(),
1✔
5210
                                    methodVisitor,
5211
                                    instrumentedType,
5212
                                    methodPool,
5213
                                    annotationValueFilterFactory,
5214
                                    (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && implementationContext.getClassFileVersion().isAtLeast(ClassFileVersion.JAVA_V6),
1✔
5215
                                    (readerFlags & ClassReader.EXPAND_FRAMES) != 0));
5216
                        } else {
5217
                            SignatureKey key = new SignatureKey(internalName, descriptor);
1✔
5218
                            methodsKeys.add(key);
1✔
5219
                            MethodDescription methodDescription = declarableMethods.remove(key);
1✔
5220
                            return methodDescription == null
1✔
5221
                                    ? cv.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionName)
1✔
5222
                                    : redefine(methodDescription, (modifiers & Opcodes.ACC_ABSTRACT) != 0, modifiers, genericSignature);
1✔
5223
                        }
5224
                    }
5225

5226
                    /**
5227
                     * Redefines a given method if this is required by looking up a potential implementation from the
5228
                     * {@link net.bytebuddy.dynamic.scaffold.TypeWriter.MethodPool}.
5229
                     *
5230
                     * @param methodDescription The method being considered for redefinition.
5231
                     * @param abstractOrigin    {@code true} if the original method is abstract, i.e. there is no implementation to preserve.
5232
                     * @param modifiers         The original modifiers of the transformed method.
5233
                     * @param genericSignature  The method's original generic signature which can be {@code null}.
5234
                     * @return A method visitor which is capable of consuming the original method.
5235
                     */
5236
                    @MaybeNull
5237
                    protected MethodVisitor redefine(MethodDescription methodDescription, boolean abstractOrigin, int modifiers, @MaybeNull String genericSignature) {
5238
                        MethodPool.Record record = methodPool.target(methodDescription);
1✔
5239
                        if (!record.getSort().isDefined()) {
1✔
5240
                            return cv.visitMethod(methodDescription.getActualModifiers() | resolveDeprecationModifiers(modifiers),
×
5241
                                    methodDescription.getInternalName(),
×
5242
                                    methodDescription.getDescriptor(),
×
5243
                                    TypeDescription.AbstractBase.RAW_TYPES
5244
                                            ? genericSignature
5245
                                            : methodDescription.getGenericSignature(),
×
5246
                                    methodDescription.getExceptionTypes().asErasures().toInternalNames());
×
5247
                        }
5248
                        MethodDescription implementedMethod = record.getMethod();
1✔
5249
                        MethodVisitor methodVisitor = cv.visitMethod(ModifierContributor.Resolver
1✔
5250
                                        .of(Collections.singleton(record.getVisibility()))
1✔
5251
                                        .resolve(implementedMethod.getActualModifiers(record.getSort().isImplemented())) | resolveDeprecationModifiers(modifiers),
1✔
5252
                                implementedMethod.getInternalName(),
1✔
5253
                                implementedMethod.getDescriptor(),
1✔
5254
                                TypeDescription.AbstractBase.RAW_TYPES
5255
                                        ? genericSignature
5256
                                        : implementedMethod.getGenericSignature(),
1✔
5257
                                implementedMethod.getExceptionTypes().asErasures().toInternalNames());
1✔
5258
                        if (methodVisitor == null) {
1✔
5259
                            return IGNORE_METHOD;
×
5260
                        } else if (abstractOrigin) {
1✔
5261
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
1✔
5262
                        } else if (methodDescription.isNative()) {
1✔
5263
                            MethodRebaseResolver.Resolution resolution = methodRebaseResolver.resolve(implementedMethod.asDefined());
×
5264
                            if (resolution.isRebased()) {
×
5265
                                MethodVisitor rebasedMethodVisitor = super.visitMethod(resolution.getResolvedMethod().getActualModifiers()
×
5266
                                                | resolveDeprecationModifiers(modifiers),
×
5267
                                        resolution.getResolvedMethod().getInternalName(),
×
5268
                                        resolution.getResolvedMethod().getDescriptor(),
×
5269
                                        TypeDescription.AbstractBase.RAW_TYPES
5270
                                                ? genericSignature
5271
                                                : implementedMethod.getGenericSignature(),
×
5272
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
×
5273
                                if (rebasedMethodVisitor != null) {
×
5274
                                    rebasedMethodVisitor.visitEnd();
×
5275
                                }
5276
                            }
5277
                            return new AttributeObtainingMethodVisitor(methodVisitor, record);
×
5278
                        } else {
5279
                            return new CodePreservingMethodVisitor(methodVisitor, record, methodRebaseResolver.resolve(implementedMethod.asDefined()));
1✔
5280
                        }
5281
                    }
5282

5283
                    @Override
5284
                    protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
5285
                        if (!internalName.equals(instrumentedType.getInternalName())) {
1✔
5286
                            TypeDescription declaredType = declaredTypes.remove(internalName);
1✔
5287
                            if (declaredType == null) {
1✔
5288
                                cv.visitInnerClass(internalName, outerName, innerName, modifiers);
1✔
5289
                            } else {
5290
                                cv.visitInnerClass(internalName,
1✔
5291
                                        // The second condition is added to retain the structure of some Java 6 compiled classes
5292
                                        declaredType.isMemberType() || outerName != null && innerName == null && declaredType.isAnonymousType()
1✔
5293
                                                ? instrumentedType.getInternalName()
1✔
5294
                                                : NO_REFERENCE,
1✔
5295
                                        declaredType.isAnonymousType()
1✔
5296
                                                ? NO_REFERENCE
1✔
5297
                                                : declaredType.getSimpleName(),
1✔
5298
                                        declaredType.getModifiers());
1✔
5299
                            }
5300
                        }
5301
                    }
1✔
5302

5303
                    @Override
5304
                    protected void onVisitNestMember(String nestMember) {
5305
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
5306
                            cv.visitNestMember(nestMember);
×
5307
                        }
5308
                    }
×
5309

5310
                    @Override
5311
                    protected void onVisitEnd() {
5312
                        for (String nestMember : nestMembers) {
1✔
5313
                            cv.visitNestMember(nestMember);
×
5314
                        }
×
5315
                        if (permittedSubclasses != null) {
1✔
5316
                            for (String permittedSubclass : permittedSubclasses) {
×
5317
                                cv.visitPermittedSubclass(permittedSubclass);
×
5318
                            }
×
5319
                        }
5320
                        TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
5321
                        if (declaringType != null) {
1✔
5322
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5323
                                    declaringType.getInternalName(),
1✔
5324
                                    instrumentedType.getSimpleName(),
1✔
5325
                                    instrumentedType.getModifiers());
1✔
5326
                        } else if (instrumentedType.isLocalType()) {
1✔
5327
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5328
                                    NO_REFERENCE,
1✔
5329
                                    instrumentedType.getSimpleName(),
1✔
5330
                                    instrumentedType.getModifiers());
1✔
5331
                        } else if (instrumentedType.isAnonymousType()) {
1✔
5332
                            cv.visitInnerClass(instrumentedType.getInternalName(),
1✔
5333
                                    NO_REFERENCE,
1✔
5334
                                    NO_REFERENCE,
1✔
5335
                                    instrumentedType.getModifiers());
1✔
5336
                        }
5337
                        for (TypeDescription typeDescription : declaredTypes.values()) {
1✔
5338
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
5339
                                    typeDescription.isMemberType()
×
5340
                                            ? instrumentedType.getInternalName()
×
5341
                                            : NO_REFERENCE,
×
5342
                                    typeDescription.isAnonymousType()
×
5343
                                            ? NO_REFERENCE
×
5344
                                            : typeDescription.getSimpleName(),
×
5345
                                    typeDescription.getModifiers());
×
5346
                        }
×
5347
                        for (RecordComponentDescription recordComponent : declarableRecordComponents.values()) {
1✔
5348
                            recordComponentPool.target(recordComponent).apply(cv, annotationValueFilterFactory);
×
5349
                        }
×
5350
                        for (FieldDescription fieldDescription : declarableFields.values()) {
1✔
5351
                            fieldPool.target(fieldDescription).apply(new DeduplicatingClassVisitor(cv), annotationValueFilterFactory);
1✔
5352
                        }
1✔
5353
                        for (MethodDescription methodDescription : declarableMethods.values()) {
1✔
5354
                            methodPool.target(methodDescription).apply(new DeduplicatingClassVisitor(cv),
1✔
5355
                                    implementationContext,
5356
                                    annotationValueFilterFactory);
5357
                        }
1✔
5358
                        initializationHandler.complete(cv, implementationContext);
1✔
5359
                        cv.visitEnd();
1✔
5360
                    }
1✔
5361

5362
                    /**
5363
                     * Returns {@link Opcodes#ACC_DEPRECATED} if the current class file version only represents deprecated methods using modifiers
5364
                     * that are not exposed in the type description API what is true for class files before Java 5 and if the supplied modifiers indicate
5365
                     * deprecation.
5366
                     *
5367
                     * @param modifiers The original modifiers.
5368
                     * @return {@link Opcodes#ACC_DEPRECATED} if the supplied modifiers imply deprecation.
5369
                     */
5370
                    private int resolveDeprecationModifiers(int modifiers) {
5371
                        return retainDeprecationModifiers && (modifiers & Opcodes.ACC_DEPRECATED) != 0
1✔
5372
                                ? Opcodes.ACC_DEPRECATED
5373
                                : ModifierContributor.EMPTY_MASK;
5374
                    }
5375

5376
                    /**
5377
                     * A class visitor that deduplicates fields and methods, mostly when access bridge methods are
5378
                     * previously declared, but incomplete.
5379
                     */
5380
                    protected class DeduplicatingClassVisitor extends ClassVisitor {
5381

5382
                        /**
5383
                         * Creates a new method deduplicating class visitor.
5384
                         *
5385
                         * @param classVisitor The class visitor to delegate to.
5386
                         */
5387
                        protected DeduplicatingClassVisitor(ClassVisitor classVisitor) {
1✔
5388
                            super(OpenedClassReader.ASM_API, classVisitor);
1✔
5389
                        }
1✔
5390

5391
                        @Override
5392
                        @MaybeNull
5393
                        public FieldVisitor visitField(int access,
5394
                                                       String internalName,
5395
                                                       String descriptor,
5396
                                                       @MaybeNull String signature,
5397
                                                       @MaybeNull Object value) {
5398
                            if (fieldKeys.contains(new SignatureKey(internalName, descriptor))) {
1✔
5399
                                throw new IllegalStateException("Field already defined: " + internalName + descriptor);
×
5400
                            }
5401
                            return super.visitField(access, internalName, descriptor, signature, value);
1✔
5402
                        }
5403

5404
                        @Override
5405
                        @MaybeNull
5406
                        public MethodVisitor visitMethod(int access,
5407
                                                         String internalName,
5408
                                                         String descriptor,
5409
                                                         @MaybeNull String signature,
5410
                                                         @MaybeNull String[] exception) {
5411
                            if (methodsKeys.contains(new SignatureKey(internalName, descriptor))) {
1✔
5412
                                if ((access & Opcodes.ACC_BRIDGE) != 0) {
×
5413
                                    return null;
×
5414
                                } else {
5415
                                    throw new IllegalStateException("Method already defined: " + internalName + descriptor);
×
5416
                                }
5417
                            }
5418
                            return super.visitMethod(access, internalName, descriptor, signature, exception);
1✔
5419
                        }
5420
                    }
5421

5422
                    /**
5423
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5424
                     * class file but that discards all code.
5425
                     */
5426
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5427

5428
                        /**
5429
                         * The field pool record to apply onto the field visitor.
5430
                         */
5431
                        private final FieldPool.Record record;
5432

5433
                        /**
5434
                         * Creates a new attribute obtaining field visitor.
5435
                         *
5436
                         * @param fieldVisitor The field visitor to delegate to.
5437
                         * @param record       The field pool record to apply onto the field visitor.
5438
                         */
5439
                        protected AttributeObtainingFieldVisitor(FieldVisitor fieldVisitor, FieldPool.Record record) {
1✔
5440
                            super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
5441
                            this.record = record;
1✔
5442
                        }
1✔
5443

5444
                        @Override
5445
                        @MaybeNull
5446
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5447
                            return annotationRetention.isEnabled()
×
5448
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5449
                                    : IGNORE_ANNOTATION;
×
5450
                        }
5451

5452
                        @Override
5453
                        @MaybeNull
5454
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5455
                            return annotationRetention.isEnabled()
1✔
5456
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5457
                                    : IGNORE_ANNOTATION;
1✔
5458
                        }
5459

5460
                        @Override
5461
                        public void visitEnd() {
5462
                            record.apply(fv, annotationValueFilterFactory);
1✔
5463
                            super.visitEnd();
1✔
5464
                        }
1✔
5465
                    }
5466

5467
                    /**
5468
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5469
                     * in the class file but discards all code.
5470
                     */
5471
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5472

5473
                        /**
5474
                         * The record component pool record to apply onto the record component visitor.
5475
                         */
5476
                        private final RecordComponentPool.Record record;
5477

5478
                        /**
5479
                         * Creates a new attribute obtaining record component visitor.
5480
                         *
5481
                         * @param recordComponentVisitor The record component visitor to delegate to.
5482
                         * @param record                 The record component pool record to apply onto the record component visitor.
5483
                         */
5484
                        protected AttributeObtainingRecordComponentVisitor(RecordComponentVisitor recordComponentVisitor, RecordComponentPool.Record record) {
×
5485
                            super(OpenedClassReader.ASM_API, recordComponentVisitor);
×
5486
                            this.record = record;
×
5487
                        }
×
5488

5489
                        @Override
5490
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5491
                            return annotationRetention.isEnabled()
×
5492
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5493
                                    : IGNORE_ANNOTATION;
×
5494
                        }
5495

5496
                        @Override
5497
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5498
                            return annotationRetention.isEnabled()
×
5499
                                    ? super.visitAnnotation(descriptor, visible)
×
5500
                                    : IGNORE_ANNOTATION;
×
5501
                        }
5502

5503
                        @Override
5504
                        public void visitEnd() {
5505
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5506
                            super.visitEnd();
×
5507
                        }
×
5508
                    }
5509

5510
                    /**
5511
                     * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5512
                     * method while copying all attributes and annotations to the actual method.
5513
                     */
5514
                    protected class CodePreservingMethodVisitor extends MethodVisitor {
5515

5516
                        /**
5517
                         * The method visitor of the actual method.
5518
                         */
5519
                        private final MethodVisitor actualMethodVisitor;
5520

5521
                        /**
5522
                         * The method pool entry to apply.
5523
                         */
5524
                        private final MethodPool.Record record;
5525

5526
                        /**
5527
                         * The resolution of a potential rebased method.
5528
                         */
5529
                        private final MethodRebaseResolver.Resolution resolution;
5530

5531
                        /**
5532
                         * Creates a new code preserving method visitor.
5533
                         *
5534
                         * @param actualMethodVisitor The method visitor of the actual method.
5535
                         * @param record              The method pool entry to apply.
5536
                         * @param resolution          The resolution of the method rebase resolver in use.
5537
                         */
5538
                        protected CodePreservingMethodVisitor(MethodVisitor actualMethodVisitor,
5539
                                                              MethodPool.Record record,
5540
                                                              MethodRebaseResolver.Resolution resolution) {
1✔
5541
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5542
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5543
                            this.record = record;
1✔
5544
                            this.resolution = resolution;
1✔
5545
                            record.applyHead(actualMethodVisitor);
1✔
5546
                        }
1✔
5547

5548
                        @Override
5549
                        @MaybeNull
5550
                        public AnnotationVisitor visitAnnotationDefault() {
5551
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5552
                        }
5553

5554
                        @Override
5555
                        @MaybeNull
5556
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5557
                            return annotationRetention.isEnabled()
×
5558
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5559
                                    : IGNORE_ANNOTATION;
×
5560
                        }
5561

5562
                        @Override
5563
                        @MaybeNull
5564
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5565
                            return annotationRetention.isEnabled()
1✔
5566
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5567
                                    : IGNORE_ANNOTATION;
1✔
5568
                        }
5569

5570
                        @Override
5571
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5572
                            if (annotationRetention.isEnabled()) {
1✔
5573
                                super.visitAnnotableParameterCount(count, visible);
1✔
5574
                            }
5575
                        }
1✔
5576

5577
                        @Override
5578
                        @MaybeNull
5579
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5580
                            return annotationRetention.isEnabled()
1✔
5581
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
1✔
5582
                                    : IGNORE_ANNOTATION;
1✔
5583
                        }
5584

5585
                        @Override
5586
                        public void visitCode() {
5587
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5588
                            actualMethodVisitor.visitEnd();
1✔
5589
                            if (resolution.isRebased()) {
1✔
5590
                                mv = cv.visitMethod(resolution.getResolvedMethod().getActualModifiers(),
1✔
5591
                                        resolution.getResolvedMethod().getInternalName(),
1✔
5592
                                        resolution.getResolvedMethod().getDescriptor(),
1✔
5593
                                        resolution.getResolvedMethod().getGenericSignature(),
1✔
5594
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
5595
                                super.visitCode();
1✔
5596
                                if (!resolution.getAppendedParameters().isEmpty() && implementationContext.getFrameGeneration().isActive()) {
1✔
5597
                                    if (implementationContext.getFrameGeneration() == Implementation.Context.FrameGeneration.GENERATE && resolution.getAppendedParameters().size() < 4) {
1✔
5598
                                        super.visitFrame(Opcodes.F_CHOP, resolution.getAppendedParameters().size(), EMPTY, EMPTY.length, EMPTY);
1✔
5599
                                    } else {
5600
                                        Object[] frame = new Object[resolution.getResolvedMethod().getParameters().size()
1✔
5601
                                                - resolution.getAppendedParameters().size()
1✔
5602
                                                + 1];
5603
                                        frame[0] = Opcodes.UNINITIALIZED_THIS;
1✔
5604
                                        for (int index = 1; index < frame.length; index++) {
1✔
5605
                                            TypeDefinition typeDefinition = resolution.getResolvedMethod()
1✔
5606
                                                    .getParameters()
1✔
5607
                                                    .get(index - 1)
1✔
5608
                                                    .getType();
1✔
5609
                                            if (typeDefinition.represents(boolean.class)
1✔
5610
                                                    || typeDefinition.represents(byte.class)
1✔
5611
                                                    || typeDefinition.represents(short.class)
1✔
5612
                                                    || typeDefinition.represents(char.class)
1✔
5613
                                                    || typeDefinition.represents(int.class)) {
1✔
5614
                                                frame[index] = Opcodes.INTEGER;
×
5615
                                            } else if (typeDefinition.represents(long.class)) {
1✔
5616
                                                frame[index] = Opcodes.LONG;
×
5617
                                            } else if (typeDefinition.represents(float.class)) {
1✔
5618
                                                frame[index] = Opcodes.FLOAT;
×
5619
                                            } else if (typeDefinition.represents(double.class)) {
1✔
5620
                                                frame[index] = Opcodes.DOUBLE;
×
5621
                                            } else {
5622
                                                frame[index] = typeDefinition.asErasure().getInternalName();
1✔
5623
                                            }
5624
                                        }
5625
                                        super.visitFrame((readerFlags & ClassReader.EXPAND_FRAMES) == 0
1✔
5626
                                                ? Opcodes.F_FULL
5627
                                                : Opcodes.F_NEW, frame.length, frame, EMPTY.length, EMPTY);
1✔
5628
                                    }
5629
                                    super.visitInsn(Opcodes.NOP);
1✔
5630
                                }
5631
                            } else {
5632
                                mv = IGNORE_METHOD;
1✔
5633
                                super.visitCode();
1✔
5634
                            }
5635
                        }
1✔
5636

5637
                        @Override
5638
                        public void visitMaxs(int stackSize, int localVariableLength) {
5639
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5640
                        }
1✔
5641
                    }
5642

5643
                    /**
5644
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5645
                     * class file but that discards all code.
5646
                     */
5647
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5648

5649
                        /**
5650
                         * The method visitor to which the actual method is to be written to.
5651
                         */
5652
                        private final MethodVisitor actualMethodVisitor;
5653

5654
                        /**
5655
                         * The method pool entry to apply.
5656
                         */
5657
                        private final MethodPool.Record record;
5658

5659
                        /**
5660
                         * Creates a new attribute obtaining method visitor.
5661
                         *
5662
                         * @param actualMethodVisitor The method visitor of the actual method.
5663
                         * @param record              The method pool entry to apply.
5664
                         */
5665
                        protected AttributeObtainingMethodVisitor(MethodVisitor actualMethodVisitor, MethodPool.Record record) {
1✔
5666
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5667
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5668
                            this.record = record;
1✔
5669
                            record.applyHead(actualMethodVisitor);
1✔
5670
                        }
1✔
5671

5672
                        @Override
5673
                        @MaybeNull
5674
                        public AnnotationVisitor visitAnnotationDefault() {
5675
                            return IGNORE_ANNOTATION;
×
5676
                        }
5677

5678
                        @Override
5679
                        @MaybeNull
5680
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5681
                            return annotationRetention.isEnabled()
×
5682
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5683
                                    : IGNORE_ANNOTATION;
×
5684
                        }
5685

5686
                        @Override
5687
                        @MaybeNull
5688
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5689
                            return annotationRetention.isEnabled()
×
5690
                                    ? super.visitAnnotation(descriptor, visible)
×
5691
                                    : IGNORE_ANNOTATION;
×
5692
                        }
5693

5694
                        @Override
5695
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5696
                            if (annotationRetention.isEnabled()) {
×
5697
                                super.visitAnnotableParameterCount(count, visible);
×
5698
                            }
5699
                        }
×
5700

5701
                        @Override
5702
                        @MaybeNull
5703
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5704
                            return annotationRetention.isEnabled()
×
5705
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
5706
                                    : IGNORE_ANNOTATION;
×
5707
                        }
5708

5709
                        @Override
5710
                        public void visitCode() {
5711
                            mv = IGNORE_METHOD;
×
5712
                        }
×
5713

5714
                        @Override
5715
                        public void visitEnd() {
5716
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5717
                            actualMethodVisitor.visitEnd();
1✔
5718
                        }
1✔
5719
                    }
5720
                }
5721
            }
5722

5723
            /**
5724
             * A default type writer that only applies a type decoration.
5725
             *
5726
             * @param <V> The best known loaded type for the dynamically created type.
5727
             */
5728
            protected static class WithDecorationOnly<V> extends ForInlining<V> {
5729

5730
                /**
5731
                 * Creates a new inlining type writer that only applies a decoration.
5732
                 *
5733
                 * @param instrumentedType             The instrumented type to be created.
5734
                 * @param classFileVersion             The class file specified by the user.
5735
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
5736
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
5737
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5738
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5739
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5740
                 * @param annotationRetention          The annotation retention to apply.
5741
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5742
                 * @param implementationContextFactory The implementation context factory to apply.
5743
                 * @param typeValidation               Determines if a type should be explicitly validated.
5744
                 * @param classReaderFactory           The class reader factory to use.
5745
                 * @param classWriterFactory           The class writer factory to use.
5746
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
5747
                 * @param classFileLocator             The class file locator for locating the original type's class file.
5748
                 */
5749
                protected WithDecorationOnly(TypeDescription instrumentedType,
5750
                                             ClassFileVersion classFileVersion,
5751
                                             List<? extends DynamicType> auxiliaryTypes,
5752
                                             MethodList<?> methods,
5753
                                             TypeAttributeAppender typeAttributeAppender,
5754
                                             AsmVisitorWrapper asmVisitorWrapper,
5755
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
5756
                                             AnnotationRetention annotationRetention,
5757
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5758
                                             Implementation.Context.Factory implementationContextFactory,
5759
                                             TypeValidation typeValidation,
5760
                                             AsmClassReader.Factory classReaderFactory,
5761
                                             AsmClassWriter.Factory classWriterFactory,
5762
                                             TypePool typePool,
5763
                                             ClassFileLocator classFileLocator) {
5764
                    super(instrumentedType,
1✔
5765
                            classFileVersion,
5766
                            FieldPool.Disabled.INSTANCE,
5767
                            RecordComponentPool.Disabled.INSTANCE,
5768
                            auxiliaryTypes,
5769
                            new LazyFieldList(instrumentedType),
5770
                            methods,
5771
                            new MethodList.Empty<MethodDescription>(),
5772
                            new RecordComponentList.Empty<RecordComponentDescription.InDefinedShape>(),
5773
                            LoadedTypeInitializer.NoOp.INSTANCE,
5774
                            TypeInitializer.None.INSTANCE,
5775
                            typeAttributeAppender,
5776
                            asmVisitorWrapper,
5777
                            annotationValueFilterFactory,
5778
                            annotationRetention,
5779
                            auxiliaryTypeNamingStrategy,
5780
                            implementationContextFactory,
5781
                            typeValidation,
5782
                            classReaderFactory,
5783
                            classWriterFactory,
5784
                            typePool,
5785
                            instrumentedType,
5786
                            classFileLocator);
5787
                }
1✔
5788

5789
                /**
5790
                 * {@inheritDoc}
5791
                 */
5792
                protected ClassVisitor writeTo(ClassVisitor classVisitor,
5793
                                               TypeInitializer typeInitializer,
5794
                                               ContextRegistry contextRegistry,
5795
                                               int writerFlags,
5796
                                               int readerFlags) {
5797
                    if (typeInitializer.isDefined()) {
1✔
5798
                        throw new UnsupportedOperationException("Cannot apply a type initializer for a decoration");
×
5799
                    }
5800
                    return new DecorationClassVisitor(classVisitor, contextRegistry, writerFlags, readerFlags);
1✔
5801
                }
5802

5803
                /**
5804
                 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5805
                 */
5806
                protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5807

5808
                    /**
5809
                     * The instrumented type.
5810
                     */
5811
                    private final TypeDescription instrumentedType;
5812

5813
                    /**
5814
                     * Creates a lazy field list.
5815
                     *
5816
                     * @param instrumentedType The instrumented type.
5817
                     */
5818
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
5819
                        this.instrumentedType = instrumentedType;
1✔
5820
                    }
1✔
5821

5822
                    /**
5823
                     * {@inheritDoc}
5824
                     */
5825
                    public FieldDescription.InDefinedShape get(int index) {
5826
                        return instrumentedType.getDeclaredFields().get(index);
×
5827
                    }
5828

5829
                    /**
5830
                     * {@inheritDoc}
5831
                     */
5832
                    public int size() {
5833
                        return instrumentedType.getDeclaredFields().size();
×
5834
                    }
5835
                }
5836

5837
                /**
5838
                 * A class visitor that decorates an existing type.
5839
                 */
5840
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
5841
                protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
5842

5843
                    /**
5844
                     * A context registry to register the lazily created implementation context to.
5845
                     */
5846
                    private final ContextRegistry contextRegistry;
5847

5848
                    /**
5849
                     * The writer flags being used.
5850
                     */
5851
                    private final int writerFlags;
5852

5853
                    /**
5854
                     * The reader flags being used.
5855
                     */
5856
                    private final int readerFlags;
5857

5858
                    /**
5859
                     * The implementation context to use or {@code null} if the context is not yet initialized.
5860
                     */
5861
                    @UnknownNull
5862
                    private Implementation.Context.ExtractableView implementationContext;
5863

5864
                    /**
5865
                     * Creates a class visitor which is capable of decorating an existent class on the fly.
5866
                     *
5867
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
5868
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
5869
                     * @param writerFlags     The writer flags being used.
5870
                     * @param readerFlags     The reader flags being used.
5871
                     */
5872
                    protected DecorationClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
1✔
5873
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
5874
                        this.contextRegistry = contextRegistry;
1✔
5875
                        this.writerFlags = writerFlags;
1✔
5876
                        this.readerFlags = readerFlags;
1✔
5877
                    }
1✔
5878

5879
                    @Override
5880
                    public void visit(int classFileVersionNumber,
5881
                                      int modifiers,
5882
                                      String internalName,
5883
                                      String genericSignature,
5884
                                      String superClassInternalName,
5885
                                      String[] interfaceTypeInternalName) {
5886
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5887
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5888
                                auxiliaryTypeNamingStrategy,
5889
                                typeInitializer,
5890
                                classFileVersion,
5891
                                WithDecorationOnly.this.classFileVersion,
5892
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5893
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5894
                                        : Implementation.Context.FrameGeneration.DISABLED);
5895
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5896
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5897
                                cv,
5898
                                implementationContext,
5899
                                typePool,
5900
                                fields,
5901
                                methods,
5902
                                writerFlags,
5903
                                readerFlags);
5904
                        cv.visit(classFileVersionNumber, modifiers, internalName, genericSignature, superClassInternalName, interfaceTypeInternalName);
1✔
5905
                    }
1✔
5906

5907
                    @Override
5908
                    @MaybeNull
5909
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5910
                        return annotationRetention.isEnabled()
×
5911
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5912
                                : IGNORE_ANNOTATION;
×
5913
                    }
5914

5915
                    @Override
5916
                    @MaybeNull
5917
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5918
                        return annotationRetention.isEnabled()
1✔
5919
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5920
                                : IGNORE_ANNOTATION;
1✔
5921
                    }
5922

5923
                    @Override
5924
                    protected void onAfterAttributes() {
5925
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5926
                    }
1✔
5927

5928
                    @Override
5929
                    protected void onVisitEnd() {
5930
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
5931
                        cv.visitEnd();
1✔
5932
                    }
1✔
5933

5934
                    /**
5935
                     * {@inheritDoc}
5936
                     */
5937
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
5938
                        /* do nothing */
5939
                    }
1✔
5940
                }
5941
            }
5942
        }
5943

5944
        /**
5945
         * A type writer that creates a class file that is not based upon another, existing class.
5946
         *
5947
         * @param <U> The best known loaded type for the dynamically created type.
5948
         */
5949
        @HashCodeAndEqualsPlugin.Enhance
5950
        public static class ForCreation<U> extends Default<U> {
5951

5952
            /**
5953
             * The method pool to use.
5954
             */
5955
            private final MethodPool methodPool;
5956

5957
            /**
5958
             * Creates a new default type writer for creating a new type that is not based on an existing class file.
5959
             *
5960
             * @param instrumentedType             The instrumented type to be created.
5961
             * @param classFileVersion             The class file version to write the instrumented type in and to apply when creating auxiliary types.
5962
             * @param fieldPool                    The field pool to use.
5963
             * @param methodPool                   The method pool to use.
5964
             * @param recordComponentPool          The record component pool to use.
5965
             * @param auxiliaryTypes               A list of auxiliary types to add to the created type.
5966
             * @param fields                       The instrumented type's declared fields.
5967
             * @param methods                      The instrumented type's declared and virtually inherited methods.
5968
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
5969
             * @param recordComponents             The instrumented type's record components.
5970
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
5971
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
5972
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5973
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5974
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
5975
             * @param annotationRetention          The annotation retention to apply.
5976
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5977
             * @param implementationContextFactory The implementation context factory to apply.
5978
             * @param typeValidation               Determines if a type should be explicitly validated.
5979
             * @param classReaderFactory           The class reader factory to use.
5980
             * @param classWriterFactory           The class writer factory to use.
5981
             * @param typePool                     The type pool to use for computing stack map frames, if required.
5982
             */
5983
            protected ForCreation(TypeDescription instrumentedType,
5984
                                  ClassFileVersion classFileVersion,
5985
                                  FieldPool fieldPool,
5986
                                  MethodPool methodPool,
5987
                                  RecordComponentPool recordComponentPool,
5988
                                  List<? extends DynamicType> auxiliaryTypes,
5989
                                  FieldList<FieldDescription.InDefinedShape> fields,
5990
                                  MethodList<?> methods,
5991
                                  MethodList<?> instrumentedMethods,
5992
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
5993
                                  LoadedTypeInitializer loadedTypeInitializer,
5994
                                  TypeInitializer typeInitializer,
5995
                                  TypeAttributeAppender typeAttributeAppender,
5996
                                  AsmVisitorWrapper asmVisitorWrapper,
5997
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
5998
                                  AnnotationRetention annotationRetention,
5999
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
6000
                                  Implementation.Context.Factory implementationContextFactory,
6001
                                  TypeValidation typeValidation,
6002
                                  AsmClassReader.Factory classReaderFactory,
6003
                                  AsmClassWriter.Factory classWriterFactory,
6004
                                  TypePool typePool) {
6005
                super(instrumentedType,
1✔
6006
                        classFileVersion,
6007
                        fieldPool,
6008
                        recordComponentPool,
6009
                        auxiliaryTypes,
6010
                        fields,
6011
                        methods,
6012
                        instrumentedMethods,
6013
                        recordComponents,
6014
                        loadedTypeInitializer,
6015
                        typeInitializer,
6016
                        typeAttributeAppender,
6017
                        asmVisitorWrapper,
6018
                        annotationValueFilterFactory,
6019
                        annotationRetention,
6020
                        auxiliaryTypeNamingStrategy,
6021
                        implementationContextFactory,
6022
                        typeValidation,
6023
                        classReaderFactory,
6024
                        classWriterFactory,
6025
                        typePool);
6026
                this.methodPool = methodPool;
1✔
6027
            }
1✔
6028

6029
            /**
6030
             * {@inheritDoc}
6031
             */
6032
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
6033
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6034
                        auxiliaryTypeNamingStrategy,
6035
                        typeInitializer,
6036
                        classFileVersion,
6037
                        classFileVersion,
6038
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6039
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6040
                                : Implementation.Context.FrameGeneration.DISABLED);
6041
                return new ImplementationContextClassVisitor(new CreationClassVisitor(asmVisitorWrapper.wrap(instrumentedType,
1✔
6042
                        ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
6043
                        implementationContext,
6044
                        typePool,
6045
                        fields,
6046
                        methods,
6047
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
6048
                        asmVisitorWrapper.mergeReader(readerFlags)), implementationContext), implementationContext);
1✔
6049
            }
6050

6051
            @Override
6052
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
6053
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
6054
                int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS), readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
6055
                AsmClassWriter classWriter = classWriterFactory.make(writerFlags, typePool);
1✔
6056
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6057
                        auxiliaryTypeNamingStrategy,
6058
                        typeInitializer,
6059
                        classFileVersion,
6060
                        classFileVersion,
6061
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6062
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6063
                                : Implementation.Context.FrameGeneration.DISABLED);
6064
                ClassVisitor classVisitor = asmVisitorWrapper.wrap(instrumentedType,
1✔
6065
                        ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
6066
                        implementationContext,
6067
                        typePool,
6068
                        fields,
6069
                        methods,
6070
                        writerFlags,
6071
                        readerFlags);
6072
                classVisitor.visit(classFileVersion.getMinorMajorVersion(),
1✔
6073
                        instrumentedType.getActualModifiers(!instrumentedType.isInterface()),
1✔
6074
                        instrumentedType.getInternalName(),
1✔
6075
                        instrumentedType.getGenericSignature(),
1✔
6076
                        (instrumentedType.getSuperClass() == null
1✔
6077
                                ? TypeDescription.ForLoadedType.of(Object.class)
1✔
6078
                                : instrumentedType.getSuperClass().asErasure()).getInternalName(),
1✔
6079
                        instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
6080
                if (!instrumentedType.isNestHost()) {
1✔
6081
                    classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
6082
                }
6083
                MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
6084
                if (enclosingMethod != null) {
1✔
6085
                    classVisitor.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
6086
                            enclosingMethod.getInternalName(),
1✔
6087
                            enclosingMethod.getDescriptor());
1✔
6088
                } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
6089
                    classVisitor.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
6090
                }
6091
                typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6092
                if (instrumentedType.isNestHost()) {
1✔
6093
                    for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
6094
                        classVisitor.visitNestMember(typeDescription.getInternalName());
×
6095
                    }
×
6096
                }
6097
                for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
1✔
6098
                    classVisitor.visitPermittedSubclass(typeDescription.getInternalName());
×
6099
                }
×
6100
                TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
6101
                if (declaringType != null) {
1✔
6102
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6103
                            declaringType.getInternalName(),
1✔
6104
                            instrumentedType.getSimpleName(),
1✔
6105
                            instrumentedType.getModifiers());
1✔
6106
                } else if (instrumentedType.isLocalType()) {
1✔
6107
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6108
                            NO_REFERENCE,
1✔
6109
                            instrumentedType.getSimpleName(),
1✔
6110
                            instrumentedType.getModifiers());
1✔
6111
                } else if (instrumentedType.isAnonymousType()) {
1✔
6112
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6113
                            NO_REFERENCE,
1✔
6114
                            NO_REFERENCE,
1✔
6115
                            instrumentedType.getModifiers());
1✔
6116
                }
6117
                for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6118
                    classVisitor.visitInnerClass(typeDescription.getInternalName(),
1✔
6119
                            typeDescription.isMemberType()
1✔
6120
                                    ? instrumentedType.getInternalName()
1✔
6121
                                    : NO_REFERENCE,
1✔
6122
                            typeDescription.isAnonymousType()
1✔
6123
                                    ? NO_REFERENCE
1✔
6124
                                    : typeDescription.getSimpleName(),
1✔
6125
                            typeDescription.getModifiers());
1✔
6126
                }
1✔
6127
                for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
6128
                    recordComponentPool.target(recordComponentDescription).apply(classVisitor, annotationValueFilterFactory);
×
6129
                }
×
6130
                for (FieldDescription fieldDescription : fields) {
1✔
6131
                    fieldPool.target(fieldDescription).apply(classVisitor, annotationValueFilterFactory);
1✔
6132
                }
1✔
6133
                for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6134
                    methodPool.target(methodDescription).apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
6135
                }
1✔
6136
                implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6137
                        methodPool,
6138
                        annotationValueFilterFactory), classVisitor, annotationValueFilterFactory);
6139
                classVisitor.visitEnd();
1✔
6140
                return new UnresolvedType(classWriter.getBinaryRepresentation(), implementationContext.getAuxiliaryTypes());
1✔
6141
            }
6142

6143
            /**
6144
             * A class visitor that applies the subclass creation as a wrapper.
6145
             */
6146
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6147

6148
                /**
6149
                 * The implementation context to apply.
6150
                 */
6151
                private final Implementation.Context.ExtractableView implementationContext;
6152

6153
                /**
6154
                 * The declared types that have been visited.
6155
                 */
6156
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6157

6158
                /**
6159
                 * The signatures of all fields that were explicitly visited.
6160
                 */
6161
                private final Set<SignatureKey> visitedFields = new HashSet<SignatureKey>();
1✔
6162

6163
                /**
6164
                 * The signature of all methods that were explicitly visited.
6165
                 */
6166
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6167

6168
                /**
6169
                 * Creates a new wrapper visitor.
6170
                 *
6171
                 * @param classVisitor          The class visitor being wrapped.
6172
                 * @param implementationContext The implementation context to apply.
6173
                 */
6174
                protected CreationClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6175
                    super(OpenedClassReader.ASM_API, classVisitor);
1✔
6176
                    this.implementationContext = implementationContext;
1✔
6177
                }
1✔
6178

6179
                @Override
6180
                protected void onAfterAttributes() {
6181
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6182
                }
1✔
6183

6184
                @Override
6185
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6186
                    declaredTypes.add(internalName);
×
6187
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
6188
                }
×
6189

6190
                @Override
6191
                @MaybeNull
6192
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6193
                    visitedFields.add(new SignatureKey(name, descriptor));
×
6194
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6195
                }
6196

6197
                @Override
6198
                @MaybeNull
6199
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
6200
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
6201
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6202
                }
6203

6204
                @Override
6205
                protected void onVisitEnd() {
6206
                    for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6207
                        if (!declaredTypes.contains(typeDescription.getInternalName())) {
×
6208
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
6209
                                    typeDescription.isMemberType()
×
6210
                                            ? instrumentedType.getInternalName()
×
6211
                                            : NO_REFERENCE,
×
6212
                                    typeDescription.isAnonymousType()
×
6213
                                            ? NO_REFERENCE
×
6214
                                            : typeDescription.getSimpleName(),
×
6215
                                    typeDescription.getModifiers());
×
6216
                        }
6217
                    }
×
6218
                    for (FieldDescription fieldDescription : fields) {
1✔
6219
                        if (!visitedFields.contains(new SignatureKey(fieldDescription.getName(), fieldDescription.getDescriptor()))) {
×
6220
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
×
6221
                        }
6222
                    }
×
6223
                    for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6224
                        if (!visitedMethods.contains(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()))) {
1✔
6225
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
6226
                        }
6227
                    }
1✔
6228
                    implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6229
                            methodPool,
1✔
6230
                            annotationValueFilterFactory), cv, annotationValueFilterFactory);
6231
                    super.onVisitEnd();
1✔
6232
                }
1✔
6233
            }
6234

6235
            /**
6236
             * A context class visitor based on an {@link Implementation.Context}.
6237
             */
6238
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6239

6240
                /**
6241
                 * The implementation context to use.
6242
                 */
6243
                private final Implementation.Context.ExtractableView implementationContext;
6244

6245
                /**
6246
                 * Creates a context class loader based on an {@link Implementation.Context}.
6247
                 *
6248
                 * @param classVisitor          The class visitor to delegate to.
6249
                 * @param implementationContext The implementation context to use.
6250
                 */
6251
                protected ImplementationContextClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6252
                    super(classVisitor);
1✔
6253
                    this.implementationContext = implementationContext;
1✔
6254
                }
1✔
6255

6256
                @Override
6257
                public List<DynamicType> getAuxiliaryTypes() {
6258
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6259
                }
6260

6261
                @Override
6262
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6263
                    return loadedTypeInitializer;
1✔
6264
                }
6265
            }
6266
        }
6267

6268
        /**
6269
         * An action to write a class file to the dumping location.
6270
         */
6271
        @HashCodeAndEqualsPlugin.Enhance
6272
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6273

6274
            /**
6275
             * Indicates that nothing is returned from this action.
6276
             */
6277
            @AlwaysNull
6278
            private static final Void NOTHING = null;
1✔
6279

6280
            /**
6281
             * The target folder for writing the class file to.
6282
             */
6283
            private final String target;
6284

6285
            /**
6286
             * The instrumented type.
6287
             */
6288
            private final TypeDescription instrumentedType;
6289

6290
            /**
6291
             * {@code true} if the dumped class file is an input to a class transformation.
6292
             */
6293
            private final boolean original;
6294

6295
            /**
6296
             * The suffix to append to the dumped class file.
6297
             */
6298
            private final long suffix;
6299

6300
            /**
6301
             * The type's binary representation.
6302
             */
6303
            private final byte[] binaryRepresentation;
6304

6305
            /**
6306
             * Creates a new class dump action.
6307
             *
6308
             * @param target               The target folder for writing the class file to.
6309
             * @param instrumentedType     The instrumented type.
6310
             * @param original             {@code true} if the dumped class file is an input to a class transformation.
6311
             * @param suffix               The suffix to append to the dumped class file.
6312
             * @param binaryRepresentation The type's binary representation.
6313
             */
6314
            protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
1✔
6315
                this.target = target;
1✔
6316
                this.instrumentedType = instrumentedType;
1✔
6317
                this.original = original;
1✔
6318
                this.suffix = suffix;
1✔
6319
                this.binaryRepresentation = binaryRepresentation;
1✔
6320
            }
1✔
6321

6322
            /**
6323
             * {@inheritDoc}
6324
             */
6325
            public Void run() throws Exception {
6326
                OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
1✔
6327
                        + (original ? "-original." : ".")
6328
                        + suffix
6329
                        + ".class"));
6330
                try {
6331
                    outputStream.write(binaryRepresentation);
1✔
6332
                    return NOTHING;
1✔
6333
                } finally {
6334
                    outputStream.close();
1✔
6335
                }
6336
            }
6337

6338
            /**
6339
             * A dispatcher for dumping class files to the file system.
6340
             */
6341
            protected interface Dispatcher {
6342

6343
                /**
6344
                 * Dumps a class file to the file system.
6345
                 *
6346
                 * @param instrumentedType     The type to dump.
6347
                 * @param original             {@code true} if the class file is in its original state.
6348
                 * @param binaryRepresentation The class file's binary representation.
6349
                 */
6350
                void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
6351

6352
                /**
6353
                 * A disabled dispatcher that does not dump any class files.
6354
                 */
6355
                enum Disabled implements Dispatcher {
1✔
6356

6357
                    /**
6358
                     * The singleton instance.
6359
                     */
6360
                    INSTANCE;
1✔
6361

6362
                    /**
6363
                     * {@inheritDoc}
6364
                     */
6365
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6366
                        /* do nothing */
6367
                    }
1✔
6368
                }
6369

6370
                /**
6371
                 * An enabled dispatcher that dumps class files to a given folder.
6372
                 */
6373
                @HashCodeAndEqualsPlugin.Enhance
6374
                class Enabled implements Dispatcher {
6375

6376
                    /**
6377
                     * The folder to write class files to.
6378
                     */
6379
                    private final String folder;
6380

6381
                    /**
6382
                     * The timestamp to append.
6383
                     */
6384
                    private final long timestamp;
6385

6386
                    /**
6387
                     * Creates a new dispatcher for dumping class files.
6388
                     *
6389
                     * @param folder    The folder to write class files to.
6390
                     * @param timestamp The timestamp to append.
6391
                     */
6392
                    protected Enabled(String folder, long timestamp) {
1✔
6393
                        this.folder = folder;
1✔
6394
                        this.timestamp = timestamp;
1✔
6395
                    }
1✔
6396

6397
                    /**
6398
                     * {@inheritDoc}
6399
                     */
6400
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6401
                        try {
6402
                            doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
1✔
6403
                        } catch (Exception exception) {
×
6404
                            exception.printStackTrace();
×
6405
                        }
1✔
6406
                    }
1✔
6407
                }
6408
            }
6409
        }
6410
    }
6411
}
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