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

raphw / byte-buddy / #642

20 Aug 2024 09:12AM CUT coverage: 85.383% (-0.006%) from 85.389%
#642

push

raphw
Delegate class reader to factories.

28757 of 33680 relevant lines covered (85.38%)

0.85 hits per line

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

81.22
/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);
1✔
2511
                    } else if (type == Integer.class) {
1✔
2512
                        int minimum, maximum;
2513
                        switch (descriptor.charAt(0)) {
1✔
2514
                            case 'Z':
2515
                                minimum = 0;
1✔
2516
                                maximum = 1;
1✔
2517
                                break;
1✔
2518
                            case 'B':
2519
                                minimum = Byte.MIN_VALUE;
1✔
2520
                                maximum = Byte.MAX_VALUE;
1✔
2521
                                break;
1✔
2522
                            case 'C':
2523
                                minimum = Character.MIN_VALUE;
1✔
2524
                                maximum = Character.MAX_VALUE;
1✔
2525
                                break;
1✔
2526
                            case 'S':
2527
                                minimum = Short.MIN_VALUE;
1✔
2528
                                maximum = Short.MAX_VALUE;
1✔
2529
                                break;
1✔
2530
                            default:
2531
                                minimum = Integer.MIN_VALUE;
1✔
2532
                                maximum = Integer.MAX_VALUE;
1✔
2533
                        }
2534
                        if ((Integer) value < minimum || (Integer) value > maximum) {
1✔
2535
                            throw new IllegalStateException("Field " + name + " defines an incompatible default value " + value);
1✔
2536
                        }
2537
                    }
2538
                }
2539
                constraint.assertField(name,
1✔
2540
                        (modifiers & Opcodes.ACC_PUBLIC) != 0,
2541
                        (modifiers & Opcodes.ACC_STATIC) != 0,
2542
                        (modifiers & Opcodes.ACC_FINAL) != 0,
2543
                        signature != null);
2544
                FieldVisitor fieldVisitor = super.visitField(modifiers, name, descriptor, signature, value);
1✔
2545
                return fieldVisitor == null
1✔
2546
                        ? IGNORE_FIELD
2547
                        : new ValidatingFieldVisitor(fieldVisitor);
2548
            }
2549

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

2570
            /**
2571
             * A constraint for members that are legal for a given type.
2572
             */
2573
            protected interface Constraint {
2574

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

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

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

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

2623
                /**
2624
                 * Asserts the legitimacy of a type annotation for the instrumented type.
2625
                 */
2626
                void assertTypeAnnotation();
2627

2628
                /**
2629
                 * Asserts if a default value is legal for a method.
2630
                 *
2631
                 * @param name The name of the method.
2632
                 */
2633
                void assertDefaultValue(String name);
2634

2635
                /**
2636
                 * Asserts if it is legal to invoke a default method from a type.
2637
                 */
2638
                void assertDefaultMethodCall();
2639

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

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

2650
                /**
2651
                 * Asserts the capability to store a method handle in the class's constant pool.
2652
                 */
2653
                void assertHandleInConstantPool();
2654

2655
                /**
2656
                 * Asserts the capability to invoke a method dynamically.
2657
                 */
2658
                void assertInvokeDynamic();
2659

2660
                /**
2661
                 * Asserts the capability of executing a subroutine.
2662
                 */
2663
                void assertSubRoutine();
2664

2665
                /**
2666
                 * Asserts the capability of storing a dynamic value in the constant pool.
2667
                 */
2668
                void assertDynamicValueInConstantPool();
2669

2670
                /**
2671
                 * Asserts the capability of storing nest mate information.
2672
                 */
2673
                void assertNestMate();
2674

2675
                /**
2676
                 * Asserts the presence of a record component.
2677
                 */
2678
                void assertRecord();
2679

2680
                /**
2681
                 * Asserts the presence of a permitted subclass.
2682
                 */
2683
                void assertPermittedSubclass();
2684

2685
                /**
2686
                 * Represents the constraint of a class type.
2687
                 */
2688
                enum ForClass implements Constraint {
1✔
2689

2690
                    /**
2691
                     * Represents the constraints of a non-abstract class.
2692
                     */
2693
                    MANIFEST(true),
1✔
2694

2695
                    /**
2696
                     * Represents the constraints of an abstract class.
2697
                     */
2698
                    ABSTRACT(false);
1✔
2699

2700
                    /**
2701
                     * {@code true} if this instance represents the constraints a non-abstract class.
2702
                     */
2703
                    private final boolean manifestType;
2704

2705
                    /**
2706
                     * Creates a new constraint for a class.
2707
                     *
2708
                     * @param manifestType {@code true} if this instance represents a non-abstract class.
2709
                     */
2710
                    ForClass(boolean manifestType) {
1✔
2711
                        this.manifestType = manifestType;
1✔
2712
                    }
1✔
2713

2714
                    /**
2715
                     * {@inheritDoc}
2716
                     */
2717
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
2718
                        /* do nothing */
2719
                    }
1✔
2720

2721
                    /**
2722
                     * {@inheritDoc}
2723
                     */
2724
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2725
                        /* do nothing */
2726
                    }
1✔
2727

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

2745
                    /**
2746
                     * {@inheritDoc}
2747
                     */
2748
                    public void assertAnnotation() {
2749
                        /* do nothing */
2750
                    }
1✔
2751

2752
                    /**
2753
                     * {@inheritDoc}
2754
                     */
2755
                    public void assertTypeAnnotation() {
2756
                        /* do nothing */
2757
                    }
1✔
2758

2759
                    /**
2760
                     * {@inheritDoc}
2761
                     */
2762
                    public void assertDefaultValue(String name) {
2763
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
1✔
2764
                    }
2765

2766
                    /**
2767
                     * {@inheritDoc}
2768
                     */
2769
                    public void assertDefaultMethodCall() {
2770
                        /* do nothing */
2771
                    }
1✔
2772

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

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

2787
                    /**
2788
                     * {@inheritDoc}
2789
                     */
2790
                    public void assertHandleInConstantPool() {
2791
                        /* do nothing */
2792
                    }
1✔
2793

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

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

2808
                    /**
2809
                     * {@inheritDoc}
2810
                     */
2811
                    public void assertDynamicValueInConstantPool() {
2812
                        /* do nothing */
2813
                    }
×
2814

2815
                    /**
2816
                     * {@inheritDoc}
2817
                     */
2818
                    public void assertNestMate() {
2819
                        /* do nothing */
2820
                    }
×
2821

2822
                    /**
2823
                     * {@inheritDoc}
2824
                     */
2825
                    public void assertRecord() {
2826
                        /* do nothing */
2827
                    }
×
2828

2829
                    /**
2830
                     * {@inheritDoc}
2831
                     */
2832
                    public void assertPermittedSubclass() {
2833
                        /* do nothing */
2834
                    }
×
2835
                }
2836

2837
                /**
2838
                 * Represents the constraint of a package type.
2839
                 */
2840
                enum ForPackageType implements Constraint {
1✔
2841

2842
                    /**
2843
                     * The singleton instance.
2844
                     */
2845
                    INSTANCE;
1✔
2846

2847
                    /**
2848
                     * {@inheritDoc}
2849
                     */
2850
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
2851
                        throw new IllegalStateException("Cannot define a field for a package description type");
1✔
2852
                    }
2853

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

2869
                    /**
2870
                     * {@inheritDoc}
2871
                     */
2872
                    public void assertAnnotation() {
2873
                        /* do nothing */
2874
                    }
1✔
2875

2876
                    /**
2877
                     * {@inheritDoc}
2878
                     */
2879
                    public void assertTypeAnnotation() {
2880
                        /* do nothing */
2881
                    }
×
2882

2883
                    /**
2884
                     * {@inheritDoc}
2885
                     */
2886
                    public void assertDefaultValue(String name) {
2887
                        /* do nothing, implicit by forbidding methods */
2888
                    }
×
2889

2890
                    /**
2891
                     * {@inheritDoc}
2892
                     */
2893
                    public void assertDefaultMethodCall() {
2894
                        /* do nothing */
2895
                    }
×
2896

2897
                    /**
2898
                     * {@inheritDoc}
2899
                     */
2900
                    public void assertTypeInConstantPool() {
2901
                        /* do nothing */
2902
                    }
×
2903

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

2911
                    /**
2912
                     * {@inheritDoc}
2913
                     */
2914
                    public void assertHandleInConstantPool() {
2915
                        /* do nothing */
2916
                    }
×
2917

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

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

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

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

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

2957
                    /**
2958
                     * {@inheritDoc}
2959
                     */
2960
                    public void assertRecord() {
2961
                        /* do nothing */
2962
                    }
×
2963

2964
                    /**
2965
                     * {@inheritDoc}
2966
                     */
2967
                    public void assertPermittedSubclass() {
2968
                        /* do nothing */
2969
                    }
×
2970
                }
2971

2972
                /**
2973
                 * Represents the constraint of an interface type.
2974
                 */
2975
                enum ForInterface implements Constraint {
1✔
2976

2977
                    /**
2978
                     * An interface type with the constraints for the Java versions 5 to 7.
2979
                     */
2980
                    CLASSIC(true),
1✔
2981

2982
                    /**
2983
                     * An interface type with the constraints for the Java versions 8+.
2984
                     */
2985
                    JAVA_8(false);
1✔
2986

2987
                    /**
2988
                     * {@code true} if this instance represents a classic interface type (pre Java 8).
2989
                     */
2990
                    private final boolean classic;
2991

2992
                    /**
2993
                     * Creates a constraint for an interface type.
2994
                     *
2995
                     * @param classic {@code true} if this instance represents a classic interface (pre Java 8).
2996
                     */
2997
                    ForInterface(boolean classic) {
1✔
2998
                        this.classic = classic;
1✔
2999
                    }
1✔
3000

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

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

3035
                    /**
3036
                     * {@inheritDoc}
3037
                     */
3038
                    public void assertAnnotation() {
3039
                        /* do nothing */
3040
                    }
1✔
3041

3042
                    /**
3043
                     * {@inheritDoc}
3044
                     */
3045
                    public void assertTypeAnnotation() {
3046
                        /* do nothing */
3047
                    }
×
3048

3049
                    /**
3050
                     * {@inheritDoc}
3051
                     */
3052
                    public void assertDefaultValue(String name) {
3053
                        throw new IllegalStateException("Cannot define default value for '" + name + "' for non-annotation type");
×
3054
                    }
3055

3056
                    /**
3057
                     * {@inheritDoc}
3058
                     */
3059
                    public void assertDefaultMethodCall() {
3060
                        /* do nothing */
3061
                    }
1✔
3062

3063
                    /**
3064
                     * {@inheritDoc}
3065
                     */
3066
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3067
                        /* do nothing */
3068
                    }
1✔
3069

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

3077
                    /**
3078
                     * {@inheritDoc}
3079
                     */
3080
                    public void assertMethodTypeInConstantPool() {
3081
                        /* do nothing */
3082
                    }
×
3083

3084
                    /**
3085
                     * {@inheritDoc}
3086
                     */
3087
                    public void assertHandleInConstantPool() {
3088
                        /* do nothing */
3089
                    }
×
3090

3091
                    /**
3092
                     * {@inheritDoc}
3093
                     */
3094
                    public void assertInvokeDynamic() {
3095
                        /* do nothing */
3096
                    }
×
3097

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

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

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

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

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

3134
                /**
3135
                 * Represents the constraint of a record type.
3136
                 */
3137
                enum ForRecord implements Constraint {
1✔
3138

3139
                    /**
3140
                     * The singleton instance.
3141
                     */
3142
                    INSTANCE;
1✔
3143

3144
                    /**
3145
                     * {@inheritDoc}
3146
                     */
3147
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3148
                        /* do nothing */
3149
                    }
×
3150

3151
                    /**
3152
                     * {@inheritDoc}
3153
                     */
3154
                    public void assertMethod(String name,
3155
                                             boolean isAbstract,
3156
                                             boolean isPublic,
3157
                                             boolean isPrivate,
3158
                                             boolean isStatic,
3159
                                             boolean isVirtual,
3160
                                             boolean isConstructor,
3161
                                             boolean isDefaultValueIncompatible,
3162
                                             boolean isGeneric) {
3163
                        /* do nothing */
3164
                    }
×
3165

3166
                    /**
3167
                     * {@inheritDoc}
3168
                     */
3169
                    public void assertAnnotation() {
3170
                        /* do nothing */
3171
                    }
×
3172

3173
                    /**
3174
                     * {@inheritDoc}
3175
                     */
3176
                    public void assertTypeAnnotation() {
3177
                        /* do nothing */
3178
                    }
×
3179

3180
                    /**
3181
                     * {@inheritDoc}
3182
                     */
3183
                    public void assertDefaultValue(String name) {
3184
                        /* do nothing */
3185
                    }
×
3186

3187
                    /**
3188
                     * {@inheritDoc}
3189
                     */
3190
                    public void assertDefaultMethodCall() {
3191
                        /* do nothing */
3192
                    }
×
3193

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

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

3210
                    /**
3211
                     * {@inheritDoc}
3212
                     */
3213
                    public void assertMethodTypeInConstantPool() {
3214
                        /* do nothing */
3215
                    }
×
3216

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

3224
                    /**
3225
                     * {@inheritDoc}
3226
                     */
3227
                    public void assertInvokeDynamic() {
3228
                        /* do nothing */
3229
                    }
×
3230

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

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

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

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

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

3267
                /**
3268
                 * Represents the constraint of an annotation type.
3269
                 */
3270
                enum ForAnnotation implements Constraint {
1✔
3271

3272
                    /**
3273
                     * An annotation type with the constraints for the Java versions 5 to 7.
3274
                     */
3275
                    CLASSIC(true),
1✔
3276

3277
                    /**
3278
                     * An annotation type with the constraints for the Java versions 8+.
3279
                     */
3280
                    JAVA_8(false);
1✔
3281

3282
                    /**
3283
                     * {@code true} if this instance represents a classic annotation type (pre Java 8).
3284
                     */
3285
                    private final boolean classic;
3286

3287
                    /**
3288
                     * Creates a constraint for an annotation type.
3289
                     *
3290
                     * @param classic {@code true} if this instance represents a classic annotation type (pre Java 8).
3291
                     */
3292
                    ForAnnotation(boolean classic) {
1✔
3293
                        this.classic = classic;
1✔
3294
                    }
1✔
3295

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

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

3328
                    /**
3329
                     * {@inheritDoc}
3330
                     */
3331
                    public void assertAnnotation() {
3332
                        /* do nothing */
3333
                    }
1✔
3334

3335
                    /**
3336
                     * {@inheritDoc}
3337
                     */
3338
                    public void assertTypeAnnotation() {
3339
                        /* do nothing */
3340
                    }
×
3341

3342
                    /**
3343
                     * {@inheritDoc}
3344
                     */
3345
                    public void assertDefaultValue(String name) {
3346
                        /* do nothing */
3347
                    }
1✔
3348

3349
                    /**
3350
                     * {@inheritDoc}
3351
                     */
3352
                    public void assertDefaultMethodCall() {
3353
                        /* do nothing */
3354
                    }
×
3355

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

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

3372
                    /**
3373
                     * {@inheritDoc}
3374
                     */
3375
                    public void assertMethodTypeInConstantPool() {
3376
                        /* do nothing */
3377
                    }
×
3378

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

3386
                    /**
3387
                     * {@inheritDoc}
3388
                     */
3389
                    public void assertInvokeDynamic() {
3390
                        /* do nothing */
3391
                    }
×
3392

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

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

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

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

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

3429
                /**
3430
                 * Represents the constraint implied by a class file version.
3431
                 */
3432
                @HashCodeAndEqualsPlugin.Enhance
3433
                class ForClassFileVersion implements Constraint {
3434

3435
                    /**
3436
                     * The enforced class file version.
3437
                     */
3438
                    private final ClassFileVersion classFileVersion;
3439

3440
                    /**
3441
                     * Creates a new constraint for the given class file version.
3442
                     *
3443
                     * @param classFileVersion The enforced class file version.
3444
                     */
3445
                    protected ForClassFileVersion(ClassFileVersion classFileVersion) {
1✔
3446
                        this.classFileVersion = classFileVersion;
1✔
3447
                    }
1✔
3448

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

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

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

3488
                    /**
3489
                     * {@inheritDoc}
3490
                     */
3491
                    public void assertAnnotation() {
3492
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3493
                            throw new IllegalStateException("Cannot write annotations for class file version " + classFileVersion);
1✔
3494
                        }
3495
                    }
1✔
3496

3497
                    /**
3498
                     * {@inheritDoc}
3499
                     */
3500
                    public void assertTypeAnnotation() {
3501
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V5)) {
1✔
3502
                            throw new IllegalStateException("Cannot write type annotations for class file version " + classFileVersion);
×
3503
                        }
3504
                    }
1✔
3505

3506
                    /**
3507
                     * {@inheritDoc}
3508
                     */
3509
                    public void assertDefaultValue(String name) {
3510
                        /* do nothing, implicitly checked by type assertion */
3511
                    }
1✔
3512

3513
                    /**
3514
                     * {@inheritDoc}
3515
                     */
3516
                    public void assertDefaultMethodCall() {
3517
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V8)) {
1✔
3518
                            throw new IllegalStateException("Cannot invoke default method for class file version " + classFileVersion);
×
3519
                        }
3520
                    }
1✔
3521

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

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

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

3549
                    /**
3550
                     * {@inheritDoc}
3551
                     */
3552
                    public void assertInvokeDynamic() {
3553
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V7)) {
1✔
3554
                            throw new IllegalStateException("Cannot write invoke dynamic instruction for class file version " + classFileVersion);
×
3555
                        }
3556
                    }
1✔
3557

3558
                    /**
3559
                     * {@inheritDoc}
3560
                     */
3561
                    public void assertSubRoutine() {
3562
                        if (classFileVersion.isGreaterThan(ClassFileVersion.JAVA_V5)) {
1✔
3563
                            throw new IllegalStateException("Cannot write subroutine for class file version " + classFileVersion);
×
3564
                        }
3565
                    }
1✔
3566

3567
                    /**
3568
                     * {@inheritDoc}
3569
                     */
3570
                    public void assertDynamicValueInConstantPool() {
3571
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
1✔
3572
                            throw new IllegalStateException("Cannot write dynamic constant for class file version " + classFileVersion);
1✔
3573
                        }
3574
                    }
×
3575

3576
                    /**
3577
                     * {@inheritDoc}
3578
                     */
3579
                    public void assertNestMate() {
3580
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V11)) {
×
3581
                            throw new IllegalStateException("Cannot define nest mate for class file version " + classFileVersion);
×
3582
                        }
3583
                    }
×
3584

3585
                    /**
3586
                     * {@inheritDoc}
3587
                     */
3588
                    public void assertRecord() {
3589
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V14)) {
1✔
3590
                            throw new IllegalStateException("Cannot define record for class file version " + classFileVersion);
1✔
3591
                        }
3592
                    }
×
3593

3594
                    /**
3595
                     * {@inheritDoc}
3596
                     */
3597
                    public void assertPermittedSubclass() {
3598
                        if (classFileVersion.isLessThan(ClassFileVersion.JAVA_V17)) {
×
3599
                            throw new IllegalStateException("Cannot define permitted subclasses for class file version " + classFileVersion);
×
3600
                        }
3601
                    }
×
3602
                }
3603

3604
                /**
3605
                 * A constraint implementation that summarizes several constraints.
3606
                 */
3607
                @HashCodeAndEqualsPlugin.Enhance
3608
                class Compound implements Constraint {
3609

3610
                    /**
3611
                     * A list of constraints that is enforced in the given order.
3612
                     */
3613
                    private final List<Constraint> constraints;
3614

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

3631
                    /**
3632
                     * {@inheritDoc}
3633
                     */
3634
                    public void assertType(int modifier, boolean definesInterfaces, boolean isGeneric) {
3635
                        for (Constraint constraint : constraints) {
1✔
3636
                            constraint.assertType(modifier, definesInterfaces, isGeneric);
1✔
3637
                        }
1✔
3638
                    }
1✔
3639

3640
                    /**
3641
                     * {@inheritDoc}
3642
                     */
3643
                    public void assertField(String name, boolean isPublic, boolean isStatic, boolean isFinal, boolean isGeneric) {
3644
                        for (Constraint constraint : constraints) {
1✔
3645
                            constraint.assertField(name, isPublic, isStatic, isFinal, isGeneric);
1✔
3646
                        }
1✔
3647
                    }
1✔
3648

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

3674
                    /**
3675
                     * {@inheritDoc}
3676
                     */
3677
                    public void assertDefaultValue(String name) {
3678
                        for (Constraint constraint : constraints) {
1✔
3679
                            constraint.assertDefaultValue(name);
1✔
3680
                        }
1✔
3681
                    }
1✔
3682

3683
                    /**
3684
                     * {@inheritDoc}
3685
                     */
3686
                    public void assertDefaultMethodCall() {
3687
                        for (Constraint constraint : constraints) {
1✔
3688
                            constraint.assertDefaultMethodCall();
1✔
3689
                        }
1✔
3690
                    }
1✔
3691

3692
                    /**
3693
                     * {@inheritDoc}
3694
                     */
3695
                    public void assertAnnotation() {
3696
                        for (Constraint constraint : constraints) {
1✔
3697
                            constraint.assertAnnotation();
1✔
3698
                        }
1✔
3699
                    }
1✔
3700

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

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

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

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

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

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

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

3764
                    /**
3765
                     * {@inheritDoc}
3766
                     */
3767
                    public void assertNestMate() {
3768
                        for (Constraint constraint : constraints) {
×
3769
                            constraint.assertNestMate();
×
3770
                        }
×
3771
                    }
×
3772

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

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

3793
            /**
3794
             * A field validator for checking default values.
3795
             */
3796
            protected class ValidatingFieldVisitor extends FieldVisitor {
3797

3798
                /**
3799
                 * Creates a validating field visitor.
3800
                 *
3801
                 * @param fieldVisitor The field visitor to which any calls are delegated to.
3802
                 */
3803
                protected ValidatingFieldVisitor(FieldVisitor fieldVisitor) {
1✔
3804
                    super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
3805
                }
1✔
3806

3807
                @Override
3808
                public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
3809
                    constraint.assertAnnotation();
1✔
3810
                    return super.visitAnnotation(descriptor, visible);
1✔
3811
                }
3812
            }
3813

3814
            /**
3815
             * A method validator for checking default values.
3816
             */
3817
            protected class ValidatingMethodVisitor extends MethodVisitor {
3818

3819
                /**
3820
                 * The name of the method being visited.
3821
                 */
3822
                private final String name;
3823

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

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

3842
                @Override
3843
                @MaybeNull
3844
                public AnnotationVisitor visitAnnotationDefault() {
3845
                    constraint.assertDefaultValue(name);
1✔
3846
                    return super.visitAnnotationDefault();
1✔
3847
                }
3848

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

3871
                @Override
3872
                public void visitMethodInsn(int opcode, String owner, String name, String descriptor, boolean isInterface) {
3873
                    if (isInterface && opcode == Opcodes.INVOKESPECIAL) {
1✔
3874
                        constraint.assertDefaultMethodCall();
1✔
3875
                    }
3876
                    super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
1✔
3877
                }
1✔
3878

3879
                @Override
3880
                public void visitInvokeDynamicInsn(String name, String descriptor, Handle bootstrapMethod, Object... bootstrapArgument) {
3881
                    constraint.assertInvokeDynamic();
1✔
3882
                    for (Object constant : bootstrapArgument) {
1✔
3883
                        if (constant instanceof ConstantDynamic) {
1✔
3884
                            constraint.assertDynamicValueInConstantPool();
×
3885
                        }
3886
                    }
3887
                    super.visitInvokeDynamicInsn(name, descriptor, bootstrapMethod, bootstrapArgument);
1✔
3888
                }
1✔
3889

3890
                @Override
3891
                public void visitJumpInsn(int opcode, Label label) {
3892
                    if (opcode == Opcodes.JSR) {
1✔
3893
                        constraint.assertSubRoutine();
1✔
3894
                    }
3895
                    super.visitJumpInsn(opcode, label);
1✔
3896
                }
1✔
3897
            }
3898
        }
3899

3900
        /**
3901
         * A type writer that inlines the created type into an existing class file.
3902
         *
3903
         * @param <U> The best known loaded type for the dynamically created type.
3904
         */
3905
        @HashCodeAndEqualsPlugin.Enhance
3906
        public abstract static class ForInlining<U> extends Default<U> {
3907

3908
            /**
3909
             * Indicates that a field should be ignored.
3910
             */
3911
            @AlwaysNull
3912
            private static final FieldVisitor IGNORE_FIELD = null;
1✔
3913

3914
            /**
3915
             * Indicates that a method should be ignored.
3916
             */
3917
            @AlwaysNull
3918
            private static final MethodVisitor IGNORE_METHOD = null;
1✔
3919

3920
            /**
3921
             * Indicates that a record component should be ignored.
3922
             */
3923
            @AlwaysNull
3924
            private static final RecordComponentVisitor IGNORE_RECORD_COMPONENT = null;
1✔
3925

3926
            /**
3927
             * Indicates that an annotation should be ignored.
3928
             */
3929
            @AlwaysNull
3930
            private static final AnnotationVisitor IGNORE_ANNOTATION = null;
1✔
3931

3932
            /**
3933
             * The original type's description.
3934
             */
3935
            protected final TypeDescription originalType;
3936

3937
            /**
3938
             * The class file locator for locating the original type's class file.
3939
             */
3940
            protected final ClassFileLocator classFileLocator;
3941

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

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

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

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

4066
            /**
4067
             * A context class visitor based on a {@link ContextRegistry}.
4068
             */
4069
            protected class RegistryContextClassVisitor extends ContextClassVisitor {
4070

4071
                /**
4072
                 * The context registry to use.
4073
                 */
4074
                private final ContextRegistry contextRegistry;
4075

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

4087
                @Override
4088
                public List<DynamicType> getAuxiliaryTypes() {
4089
                    return CompoundList.of(auxiliaryTypes, contextRegistry.getAuxiliaryTypes());
1✔
4090
                }
4091

4092
                @Override
4093
                public LoadedTypeInitializer getLoadedTypeInitializer() {
4094
                    return loadedTypeInitializer;
1✔
4095
                }
4096
            }
4097

4098
            /**
4099
             * A context registry allows to extract auxiliary types from a lazily created implementation context.
4100
             */
4101
            protected static class ContextRegistry {
1✔
4102

4103
                /**
4104
                 * The implementation context that is used for creating a class or {@code null} if it was not registered.
4105
                 */
4106
                @UnknownNull
4107
                private Implementation.Context.ExtractableView implementationContext;
4108

4109
                /**
4110
                 * Registers the implementation context.
4111
                 *
4112
                 * @param implementationContext The implementation context.
4113
                 */
4114
                public void setImplementationContext(Implementation.Context.ExtractableView implementationContext) {
4115
                    this.implementationContext = implementationContext;
1✔
4116
                }
1✔
4117

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

4130
            /**
4131
             * A default type writer that reprocesses a type completely.
4132
             *
4133
             * @param <V> The best known loaded type for the dynamically created type.
4134
             */
4135
            @HashCodeAndEqualsPlugin.Enhance
4136
            protected static class WithFullProcessing<V> extends ForInlining<V> {
4137

4138
                /**
4139
                 * An empty array to indicate missing frames.
4140
                 */
4141
                private static final Object[] EMPTY = new Object[0];
1✔
4142

4143
                /**
4144
                 * The method registry to use.
4145
                 */
4146
                private final MethodRegistry.Prepared methodRegistry;
4147

4148
                /**
4149
                 * The implementation target factory to use.
4150
                 */
4151
                private final Implementation.Target.Factory implementationTargetFactory;
4152

4153
                /**
4154
                 * The method rebase resolver to use for rebasing methods.
4155
                 */
4156
                private final MethodRebaseResolver methodRebaseResolver;
4157

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

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

4251
                /**
4252
                 * A {@link ClassRemapper} that uses the Byte Buddy-defined API version.
4253
                 */
4254
                protected static class OpenedClassRemapper extends ClassRemapper {
4255

4256
                    /**
4257
                     * Creates a new opened class remapper.
4258
                     *
4259
                     * @param classVisitor The class visitor to wrap
4260
                     * @param remapper     The remapper to apply.
4261
                     */
4262
                    protected OpenedClassRemapper(ClassVisitor classVisitor, Remapper remapper) {
4263
                        super(OpenedClassReader.ASM_API, classVisitor, remapper);
1✔
4264
                    }
1✔
4265
                }
4266

4267
                /**
4268
                 * An initialization handler is responsible for handling the creation of the type initializer.
4269
                 */
4270
                protected interface InitializationHandler {
4271

4272
                    /**
4273
                     * Invoked upon completion of writing the instrumented type.
4274
                     *
4275
                     * @param classVisitor          The class visitor to write any methods to.
4276
                     * @param implementationContext The implementation context to use.
4277
                     */
4278
                    void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext);
4279

4280
                    /**
4281
                     * An initialization handler that creates a new type initializer.
4282
                     */
4283
                    class Creating extends TypeInitializer.Drain.Default implements InitializationHandler {
4284

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

4298
                        /**
4299
                         * {@inheritDoc}
4300
                         */
4301
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4302
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4303
                        }
1✔
4304
                    }
4305

4306
                    /**
4307
                     * An initialization handler that appends code to a previously visited type initializer.
4308
                     */
4309
                    abstract class Appending extends MethodVisitor implements InitializationHandler, TypeInitializer.Drain {
4310

4311
                        /**
4312
                         * The instrumented type.
4313
                         */
4314
                        protected final TypeDescription instrumentedType;
4315

4316
                        /**
4317
                         * The method pool record for the type initializer.
4318
                         */
4319
                        protected final MethodPool.Record record;
4320

4321
                        /**
4322
                         * The used annotation value filter factory.
4323
                         */
4324
                        protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
4325

4326
                        /**
4327
                         * The frame writer to use.
4328
                         */
4329
                        protected final FrameWriter frameWriter;
4330

4331
                        /**
4332
                         * The currently recorded stack size.
4333
                         */
4334
                        protected int stackSize;
4335

4336
                        /**
4337
                         * The currently recorded local variable length.
4338
                         */
4339
                        protected int localVariableLength;
4340

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

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

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

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

4440
                        @Override
4441
                        public void visitCode() {
4442
                            record.applyAttributes(mv, annotationValueFilterFactory);
1✔
4443
                            super.visitCode();
1✔
4444
                            onStart();
1✔
4445
                        }
1✔
4446

4447
                        /**
4448
                         * Invoked after the user code was visited.
4449
                         */
4450
                        protected abstract void onStart();
4451

4452
                        @Override
4453
                        public void visitFrame(int type, int localVariableLength, @MaybeNull Object[] localVariable, int stackSize, @MaybeNull Object[] stack) {
4454
                            super.visitFrame(type, localVariableLength, localVariable, stackSize, stack);
1✔
4455
                            frameWriter.onFrame(type, localVariableLength);
1✔
4456
                        }
1✔
4457

4458
                        @Override
4459
                        public void visitMaxs(int stackSize, int localVariableLength) {
4460
                            this.stackSize = stackSize;
1✔
4461
                            this.localVariableLength = localVariableLength;
1✔
4462
                        }
1✔
4463

4464
                        @Override
4465
                        public abstract void visitEnd();
4466

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

4477
                        /**
4478
                         * Invoked upon completion of writing the type initializer.
4479
                         *
4480
                         * @param implementationContext The implementation context to use.
4481
                         */
4482
                        protected abstract void onComplete(Implementation.Context implementationContext);
4483

4484
                        /**
4485
                         * {@inheritDoc}
4486
                         */
4487
                        public void complete(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
4488
                            implementationContext.drain(this, classVisitor, annotationValueFilterFactory);
1✔
4489
                            mv.visitMaxs(stackSize, localVariableLength);
1✔
4490
                            mv.visitEnd();
1✔
4491
                        }
1✔
4492

4493
                        /**
4494
                         * A frame writer is responsible for adding empty frames on jump instructions.
4495
                         */
4496
                        protected interface FrameWriter {
4497

4498
                            /**
4499
                             * An empty array.
4500
                             */
4501
                            Object[] EMPTY = new Object[0];
1✔
4502

4503
                            /**
4504
                             * Informs this frame writer of an observed frame.
4505
                             *
4506
                             * @param type                The frame type.
4507
                             * @param localVariableLength The length of the local variables array.
4508
                             */
4509
                            void onFrame(int type, int localVariableLength);
4510

4511
                            /**
4512
                             * Emits an empty frame.
4513
                             *
4514
                             * @param methodVisitor The method visitor to write the frame to.
4515
                             */
4516
                            void emitFrame(MethodVisitor methodVisitor);
4517

4518
                            /**
4519
                             * A non-operational frame writer.
4520
                             */
4521
                            enum NoOp implements FrameWriter {
1✔
4522

4523
                                /**
4524
                                 * The singleton instance.
4525
                                 */
4526
                                INSTANCE;
1✔
4527

4528
                                /**
4529
                                 * {@inheritDoc}
4530
                                 */
4531
                                public void onFrame(int type, int localVariableLength) {
4532
                                    /* do nothing */
4533
                                }
1✔
4534

4535
                                /**
4536
                                 * {@inheritDoc}
4537
                                 */
4538
                                public void emitFrame(MethodVisitor methodVisitor) {
4539
                                    /* do nothing */
4540
                                }
1✔
4541
                            }
4542

4543
                            /**
4544
                             * A frame writer that creates an expanded frame.
4545
                             */
4546
                            enum Expanding implements FrameWriter {
1✔
4547

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

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

4560
                                /**
4561
                                 * {@inheritDoc}
4562
                                 */
4563
                                public void emitFrame(MethodVisitor methodVisitor) {
4564
                                    methodVisitor.visitFrame(Opcodes.F_NEW, EMPTY.length, EMPTY, EMPTY.length, EMPTY);
1✔
4565
                                    methodVisitor.visitInsn(Opcodes.NOP);
1✔
4566
                                }
1✔
4567
                            }
4568

4569
                            /**
4570
                             * An active frame writer that creates the most efficient frame.
4571
                             */
4572
                            class Active implements FrameWriter {
1✔
4573

4574
                                /**
4575
                                 * The current length of the current local variable array.
4576
                                 */
4577
                                private int currentLocalVariableLength;
4578

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

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

4619
                        /**
4620
                         * An initialization handler that appends code to a previously visited type initializer without allowing active
4621
                         * {@link TypeInitializer} registrations.
4622
                         */
4623
                        protected abstract static class WithoutDrain extends Appending {
4624

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

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

4649
                            @Override
4650
                            public void visitEnd() {
4651
                                /* do nothing */
4652
                            }
1✔
4653

4654
                            /**
4655
                             * An initialization handler that appends code to a previously visited type initializer without allowing active
4656
                             * {@link TypeInitializer} registrations and without an active record.
4657
                             */
4658
                            protected static class WithoutActiveRecord extends WithoutDrain {
4659

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

4675
                                @Override
4676
                                protected void onComplete(Implementation.Context implementationContext) {
4677
                                    /* do nothing */
4678
                                }
1✔
4679
                            }
4680

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

4687
                                /**
4688
                                 * The label that indicates the beginning of the active record.
4689
                                 */
4690
                                private final Label label;
4691

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

4712
                                @Override
4713
                                public void visitInsn(int opcode) {
4714
                                    if (opcode == Opcodes.RETURN) {
1✔
4715
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4716
                                    } else {
4717
                                        super.visitInsn(opcode);
1✔
4718
                                    }
4719
                                }
1✔
4720

4721
                                @Override
4722
                                protected void onComplete(Implementation.Context implementationContext) {
4723
                                    mv.visitLabel(label);
1✔
4724
                                    frameWriter.emitFrame(mv);
1✔
4725
                                    ByteCodeAppender.Size size = record.applyCode(mv, implementationContext);
1✔
4726
                                    stackSize = Math.max(stackSize, size.getOperandStackSize());
1✔
4727
                                    localVariableLength = Math.max(localVariableLength, size.getLocalVariableSize());
1✔
4728
                                }
1✔
4729

4730
                            }
4731
                        }
4732

4733
                        /**
4734
                         * An initialization handler that appends code to a previously visited type initializer with allowing active
4735
                         * {@link TypeInitializer} registrations.
4736
                         */
4737
                        protected abstract static class WithDrain extends Appending {
4738

4739
                            /**
4740
                             * A label marking the beginning of the appended code.
4741
                             */
4742
                            protected final Label appended;
4743

4744
                            /**
4745
                             * A label marking the beginning og the original type initializer's code.
4746
                             */
4747
                            protected final Label original;
4748

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

4770
                            @Override
4771
                            protected void onStart() {
4772
                                mv.visitJumpInsn(Opcodes.GOTO, appended);
1✔
4773
                                mv.visitLabel(original);
1✔
4774
                                frameWriter.emitFrame(mv);
1✔
4775
                            }
1✔
4776

4777
                            @Override
4778
                            public void visitEnd() {
4779
                                mv.visitLabel(appended);
1✔
4780
                                frameWriter.emitFrame(mv);
1✔
4781
                            }
1✔
4782

4783
                            @Override
4784
                            protected void onComplete(Implementation.Context implementationContext) {
4785
                                mv.visitJumpInsn(Opcodes.GOTO, original);
1✔
4786
                                onAfterComplete(implementationContext);
1✔
4787
                            }
1✔
4788

4789
                            /**
4790
                             * Invoked after completion of writing the type initializer.
4791
                             *
4792
                             * @param implementationContext The implementation context to use.
4793
                             */
4794
                            protected abstract void onAfterComplete(Implementation.Context implementationContext);
4795

4796
                            /**
4797
                             * A code appending initialization handler with a drain that does not apply an explicit record.
4798
                             */
4799
                            protected static class WithoutActiveRecord extends WithDrain {
4800

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

4820
                                @Override
4821
                                protected void onAfterComplete(Implementation.Context implementationContext) {
4822
                                    /* do nothing */
4823
                                }
1✔
4824
                            }
4825

4826
                            /**
4827
                             * A code appending initialization handler with a drain that applies an explicit record.
4828
                             */
4829
                            protected static class WithActiveRecord extends WithDrain {
4830

4831
                                /**
4832
                                 * A label indicating the beginning of the record's code.
4833
                                 */
4834
                                private final Label label;
4835

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

4856
                                @Override
4857
                                public void visitInsn(int opcode) {
4858
                                    if (opcode == Opcodes.RETURN) {
1✔
4859
                                        mv.visitJumpInsn(Opcodes.GOTO, label);
1✔
4860
                                    } else {
4861
                                        super.visitInsn(opcode);
1✔
4862
                                    }
4863
                                }
1✔
4864

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

4878
                /**
4879
                 * A class visitor which is capable of applying a redefinition of an existing class file.
4880
                 */
4881
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
4882
                protected class RedefinitionClassVisitor extends MetadataAwareClassVisitor {
4883

4884
                    /**
4885
                     * The type initializer to apply.
4886
                     */
4887
                    private final TypeInitializer typeInitializer;
4888

4889
                    /**
4890
                     * A context registry to register the lazily created implementation context to.
4891
                     */
4892
                    private final ContextRegistry contextRegistry;
4893

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

4899
                    /**
4900
                     * The reader flags being used.
4901
                     */
4902
                    private final int readerFlags;
4903

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

4909
                    /**
4910
                     * A mapping of methods to write by their unique signature.
4911
                     */
4912
                    private final LinkedHashMap<SignatureKey, MethodDescription> declarableMethods;
4913

4914
                    /**
4915
                     * A mapping of record components to write by their names.
4916
                     */
4917
                    private final LinkedHashMap<String, RecordComponentDescription> declarableRecordComponents;
4918

4919
                    /**
4920
                     * 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.
4921
                     */
4922
                    private final Set<String> nestMembers;
4923

4924
                    /**
4925
                     * A mapping of the internal names of all declared types to their description.
4926
                     */
4927
                    private final LinkedHashMap<String, TypeDescription> declaredTypes;
4928

4929
                    /**
4930
                     * A list of internal names of permitted subclasses to include.
4931
                     */
4932
                    @MaybeNull
4933
                    private final Set<String> permittedSubclasses;
4934

4935
                    /**
4936
                     * The method pool to use or {@code null} if the pool was not yet initialized.
4937
                     */
4938
                    @UnknownNull
4939
                    private MethodPool methodPool;
4940

4941
                    /**
4942
                     * The initialization handler to use or {@code null} if the handler was not yet initialized.
4943
                     */
4944
                    @UnknownNull
4945
                    private InitializationHandler initializationHandler;
4946

4947
                    /**
4948
                     * The implementation context for this class creation or {@code null} if it was not yet created.
4949
                     */
4950
                    @UnknownNull
4951
                    private Implementation.Context.ExtractableView implementationContext;
4952

4953
                    /**
4954
                     * {@code true} if the modifiers for deprecation should be retained.
4955
                     */
4956
                    private boolean retainDeprecationModifiers;
4957

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

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

5055
                    @Override
5056
                    protected void onVisitNestHost(String nestHost) {
5057
                        onNestHost();
×
5058
                    }
×
5059

5060
                    @Override
5061
                    protected void onNestHost() {
5062
                        if (!instrumentedType.isNestHost()) {
1✔
5063
                            cv.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
5064
                        }
5065
                    }
1✔
5066

5067
                    @Override
5068
                    protected void onVisitPermittedSubclass(String permittedSubclass) {
5069
                        if (permittedSubclasses != null && permittedSubclasses.remove(permittedSubclass)) {
×
5070
                            cv.visitPermittedSubclass(permittedSubclass);
×
5071
                        }
5072
                    }
×
5073

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

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

5096
                    @Override
5097
                    protected void onAfterAttributes() {
5098
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5099
                    }
1✔
5100

5101
                    @Override
5102
                    @MaybeNull
5103
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5104
                        return annotationRetention.isEnabled()
1✔
5105
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
1✔
5106
                                : IGNORE_ANNOTATION;
×
5107
                    }
5108

5109
                    @Override
5110
                    @MaybeNull
5111
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5112
                        return annotationRetention.isEnabled()
1✔
5113
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5114
                                : IGNORE_ANNOTATION;
1✔
5115
                    }
5116

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

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

5150
                    @Override
5151
                    @MaybeNull
5152
                    protected FieldVisitor onVisitField(int modifiers,
5153
                                                        String internalName,
5154
                                                        String descriptor,
5155
                                                        @MaybeNull String genericSignature,
5156
                                                        @MaybeNull Object value) {
5157
                        FieldDescription fieldDescription = declarableFields.remove(new SignatureKey(internalName, descriptor));
1✔
5158
                        if (fieldDescription != null) {
1✔
5159
                            FieldPool.Record record = fieldPool.target(fieldDescription);
1✔
5160
                            if (!record.isImplicit()) {
1✔
5161
                                return redefine(record, value, modifiers, genericSignature);
1✔
5162
                            }
5163
                        }
5164
                        return cv.visitField(modifiers, internalName, descriptor, genericSignature, value);
1✔
5165
                    }
5166

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

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

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

5274
                    @Override
5275
                    protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
5276
                        if (!internalName.equals(instrumentedType.getInternalName())) {
1✔
5277
                            TypeDescription declaredType = declaredTypes.remove(internalName);
1✔
5278
                            if (declaredType == null) {
1✔
5279
                                cv.visitInnerClass(internalName, outerName, innerName, modifiers);
1✔
5280
                            } else {
5281
                                cv.visitInnerClass(internalName,
1✔
5282
                                        // The second condition is added to retain the structure of some Java 6 compiled classes
5283
                                        declaredType.isMemberType() || outerName != null && innerName == null && declaredType.isAnonymousType()
1✔
5284
                                                ? instrumentedType.getInternalName()
1✔
5285
                                                : NO_REFERENCE,
1✔
5286
                                        declaredType.isAnonymousType()
1✔
5287
                                                ? NO_REFERENCE
1✔
5288
                                                : declaredType.getSimpleName(),
1✔
5289
                                        declaredType.getModifiers());
1✔
5290
                            }
5291
                        }
5292
                    }
1✔
5293

5294
                    @Override
5295
                    protected void onVisitNestMember(String nestMember) {
5296
                        if (instrumentedType.isNestHost() && nestMembers.remove(nestMember)) {
×
5297
                            cv.visitNestMember(nestMember);
×
5298
                        }
5299
                    }
×
5300

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

5351
                    /**
5352
                     * Returns {@link Opcodes#ACC_DEPRECATED} if the current class file version only represents deprecated methods using modifiers
5353
                     * that are not exposed in the type description API what is true for class files before Java 5 and if the supplied modifiers indicate
5354
                     * deprecation.
5355
                     *
5356
                     * @param modifiers The original modifiers.
5357
                     * @return {@link Opcodes#ACC_DEPRECATED} if the supplied modifiers imply deprecation.
5358
                     */
5359
                    private int resolveDeprecationModifiers(int modifiers) {
5360
                        return retainDeprecationModifiers && (modifiers & Opcodes.ACC_DEPRECATED) != 0
1✔
5361
                                ? Opcodes.ACC_DEPRECATED
5362
                                : ModifierContributor.EMPTY_MASK;
5363
                    }
5364

5365
                    /**
5366
                     * A field visitor that obtains all attributes and annotations of a field that is found in the
5367
                     * class file but that discards all code.
5368
                     */
5369
                    protected class AttributeObtainingFieldVisitor extends FieldVisitor {
5370

5371
                        /**
5372
                         * The field pool record to apply onto the field visitor.
5373
                         */
5374
                        private final FieldPool.Record record;
5375

5376
                        /**
5377
                         * Creates a new attribute obtaining field visitor.
5378
                         *
5379
                         * @param fieldVisitor The field visitor to delegate to.
5380
                         * @param record       The field pool record to apply onto the field visitor.
5381
                         */
5382
                        protected AttributeObtainingFieldVisitor(FieldVisitor fieldVisitor, FieldPool.Record record) {
1✔
5383
                            super(OpenedClassReader.ASM_API, fieldVisitor);
1✔
5384
                            this.record = record;
1✔
5385
                        }
1✔
5386

5387
                        @Override
5388
                        @MaybeNull
5389
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5390
                            return annotationRetention.isEnabled()
×
5391
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5392
                                    : IGNORE_ANNOTATION;
×
5393
                        }
5394

5395
                        @Override
5396
                        @MaybeNull
5397
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5398
                            return annotationRetention.isEnabled()
1✔
5399
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5400
                                    : IGNORE_ANNOTATION;
1✔
5401
                        }
5402

5403
                        @Override
5404
                        public void visitEnd() {
5405
                            record.apply(fv, annotationValueFilterFactory);
1✔
5406
                            super.visitEnd();
1✔
5407
                        }
1✔
5408
                    }
5409

5410
                    /**
5411
                     * A record component visitor that obtains all attributes and annotations of a record component that is found
5412
                     * in the class file but discards all code.
5413
                     */
5414
                    protected class AttributeObtainingRecordComponentVisitor extends RecordComponentVisitor {
5415

5416
                        /**
5417
                         * The record component pool record to apply onto the record component visitor.
5418
                         */
5419
                        private final RecordComponentPool.Record record;
5420

5421
                        /**
5422
                         * Creates a new attribute obtaining record component visitor.
5423
                         *
5424
                         * @param recordComponentVisitor The record component visitor to delegate to.
5425
                         * @param record                 The record component pool record to apply onto the record component visitor.
5426
                         */
5427
                        protected AttributeObtainingRecordComponentVisitor(RecordComponentVisitor recordComponentVisitor, RecordComponentPool.Record record) {
×
5428
                            super(OpenedClassReader.ASM_API, recordComponentVisitor);
×
5429
                            this.record = record;
×
5430
                        }
×
5431

5432
                        @Override
5433
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5434
                            return annotationRetention.isEnabled()
×
5435
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5436
                                    : IGNORE_ANNOTATION;
×
5437
                        }
5438

5439
                        @Override
5440
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5441
                            return annotationRetention.isEnabled()
×
5442
                                    ? super.visitAnnotation(descriptor, visible)
×
5443
                                    : IGNORE_ANNOTATION;
×
5444
                        }
5445

5446
                        @Override
5447
                        public void visitEnd() {
5448
                            record.apply(getDelegate(), annotationValueFilterFactory);
×
5449
                            super.visitEnd();
×
5450
                        }
×
5451
                    }
5452

5453
                    /**
5454
                     * A method visitor that preserves the code of a method in the class file by copying it into a rebased
5455
                     * method while copying all attributes and annotations to the actual method.
5456
                     */
5457
                    protected class CodePreservingMethodVisitor extends MethodVisitor {
5458

5459
                        /**
5460
                         * The method visitor of the actual method.
5461
                         */
5462
                        private final MethodVisitor actualMethodVisitor;
5463

5464
                        /**
5465
                         * The method pool entry to apply.
5466
                         */
5467
                        private final MethodPool.Record record;
5468

5469
                        /**
5470
                         * The resolution of a potential rebased method.
5471
                         */
5472
                        private final MethodRebaseResolver.Resolution resolution;
5473

5474
                        /**
5475
                         * Creates a new code preserving method visitor.
5476
                         *
5477
                         * @param actualMethodVisitor The method visitor of the actual method.
5478
                         * @param record              The method pool entry to apply.
5479
                         * @param resolution          The resolution of the method rebase resolver in use.
5480
                         */
5481
                        protected CodePreservingMethodVisitor(MethodVisitor actualMethodVisitor,
5482
                                                              MethodPool.Record record,
5483
                                                              MethodRebaseResolver.Resolution resolution) {
1✔
5484
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5485
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5486
                            this.record = record;
1✔
5487
                            this.resolution = resolution;
1✔
5488
                            record.applyHead(actualMethodVisitor);
1✔
5489
                        }
1✔
5490

5491
                        @Override
5492
                        @MaybeNull
5493
                        public AnnotationVisitor visitAnnotationDefault() {
5494
                            return IGNORE_ANNOTATION; // Annotation types can never be rebased.
×
5495
                        }
5496

5497
                        @Override
5498
                        @MaybeNull
5499
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5500
                            return annotationRetention.isEnabled()
×
5501
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5502
                                    : IGNORE_ANNOTATION;
×
5503
                        }
5504

5505
                        @Override
5506
                        @MaybeNull
5507
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5508
                            return annotationRetention.isEnabled()
1✔
5509
                                    ? super.visitAnnotation(descriptor, visible)
1✔
5510
                                    : IGNORE_ANNOTATION;
1✔
5511
                        }
5512

5513
                        @Override
5514
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5515
                            if (annotationRetention.isEnabled()) {
1✔
5516
                                super.visitAnnotableParameterCount(count, visible);
1✔
5517
                            }
5518
                        }
1✔
5519

5520
                        @Override
5521
                        @MaybeNull
5522
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5523
                            return annotationRetention.isEnabled()
1✔
5524
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
1✔
5525
                                    : IGNORE_ANNOTATION;
1✔
5526
                        }
5527

5528
                        @Override
5529
                        public void visitCode() {
5530
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5531
                            actualMethodVisitor.visitEnd();
1✔
5532
                            if (resolution.isRebased()) {
1✔
5533
                                mv = cv.visitMethod(resolution.getResolvedMethod().getActualModifiers(),
1✔
5534
                                        resolution.getResolvedMethod().getInternalName(),
1✔
5535
                                        resolution.getResolvedMethod().getDescriptor(),
1✔
5536
                                        resolution.getResolvedMethod().getGenericSignature(),
1✔
5537
                                        resolution.getResolvedMethod().getExceptionTypes().asErasures().toInternalNames());
1✔
5538
                                super.visitCode();
1✔
5539
                                if (!resolution.getAppendedParameters().isEmpty() && implementationContext.getFrameGeneration().isActive()) {
1✔
5540
                                    if (implementationContext.getFrameGeneration() == Implementation.Context.FrameGeneration.GENERATE && resolution.getAppendedParameters().size() < 4) {
1✔
5541
                                        super.visitFrame(Opcodes.F_CHOP, resolution.getAppendedParameters().size(), EMPTY, EMPTY.length, EMPTY);
1✔
5542
                                    } else {
5543
                                        Object[] frame = new Object[resolution.getResolvedMethod().getParameters().size()
1✔
5544
                                                - resolution.getAppendedParameters().size()
1✔
5545
                                                + 1];
5546
                                        frame[0] = Opcodes.UNINITIALIZED_THIS;
1✔
5547
                                        for (int index = 1; index < frame.length; index++) {
1✔
5548
                                            TypeDefinition typeDefinition = resolution.getResolvedMethod()
1✔
5549
                                                    .getParameters()
1✔
5550
                                                    .get(index - 1)
1✔
5551
                                                    .getType();
1✔
5552
                                            if (typeDefinition.represents(boolean.class)
1✔
5553
                                                    || typeDefinition.represents(byte.class)
1✔
5554
                                                    || typeDefinition.represents(short.class)
1✔
5555
                                                    || typeDefinition.represents(char.class)
1✔
5556
                                                    || typeDefinition.represents(int.class)) {
1✔
5557
                                                frame[index] = Opcodes.INTEGER;
×
5558
                                            } else if (typeDefinition.represents(long.class)) {
1✔
5559
                                                frame[index] = Opcodes.LONG;
×
5560
                                            } else if (typeDefinition.represents(float.class)) {
1✔
5561
                                                frame[index] = Opcodes.FLOAT;
×
5562
                                            } else if (typeDefinition.represents(double.class)) {
1✔
5563
                                                frame[index] = Opcodes.DOUBLE;
×
5564
                                            } else {
5565
                                                frame[index] = typeDefinition.asErasure().getInternalName();
1✔
5566
                                            }
5567
                                        }
5568
                                        super.visitFrame((readerFlags & ClassReader.EXPAND_FRAMES) == 0
1✔
5569
                                                ? Opcodes.F_FULL
5570
                                                : Opcodes.F_NEW, frame.length, frame, EMPTY.length, EMPTY);
1✔
5571
                                    }
5572
                                    super.visitInsn(Opcodes.NOP);
1✔
5573
                                }
5574
                            } else {
5575
                                mv = IGNORE_METHOD;
1✔
5576
                                super.visitCode();
1✔
5577
                            }
5578
                        }
1✔
5579

5580
                        @Override
5581
                        public void visitMaxs(int stackSize, int localVariableLength) {
5582
                            super.visitMaxs(stackSize, Math.max(localVariableLength, resolution.getResolvedMethod().getStackSize()));
1✔
5583
                        }
1✔
5584
                    }
5585

5586
                    /**
5587
                     * A method visitor that obtains all attributes and annotations of a method that is found in the
5588
                     * class file but that discards all code.
5589
                     */
5590
                    protected class AttributeObtainingMethodVisitor extends MethodVisitor {
5591

5592
                        /**
5593
                         * The method visitor to which the actual method is to be written to.
5594
                         */
5595
                        private final MethodVisitor actualMethodVisitor;
5596

5597
                        /**
5598
                         * The method pool entry to apply.
5599
                         */
5600
                        private final MethodPool.Record record;
5601

5602
                        /**
5603
                         * Creates a new attribute obtaining method visitor.
5604
                         *
5605
                         * @param actualMethodVisitor The method visitor of the actual method.
5606
                         * @param record              The method pool entry to apply.
5607
                         */
5608
                        protected AttributeObtainingMethodVisitor(MethodVisitor actualMethodVisitor, MethodPool.Record record) {
1✔
5609
                            super(OpenedClassReader.ASM_API, actualMethodVisitor);
1✔
5610
                            this.actualMethodVisitor = actualMethodVisitor;
1✔
5611
                            this.record = record;
1✔
5612
                            record.applyHead(actualMethodVisitor);
1✔
5613
                        }
1✔
5614

5615
                        @Override
5616
                        @MaybeNull
5617
                        public AnnotationVisitor visitAnnotationDefault() {
5618
                            return IGNORE_ANNOTATION;
×
5619
                        }
5620

5621
                        @Override
5622
                        @MaybeNull
5623
                        public AnnotationVisitor visitTypeAnnotation(int typeReference, @MaybeNull TypePath typePath, String descriptor, boolean visible) {
5624
                            return annotationRetention.isEnabled()
×
5625
                                    ? super.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5626
                                    : IGNORE_ANNOTATION;
×
5627
                        }
5628

5629
                        @Override
5630
                        @MaybeNull
5631
                        public AnnotationVisitor visitAnnotation(String descriptor, boolean visible) {
5632
                            return annotationRetention.isEnabled()
×
5633
                                    ? super.visitAnnotation(descriptor, visible)
×
5634
                                    : IGNORE_ANNOTATION;
×
5635
                        }
5636

5637
                        @Override
5638
                        public void visitAnnotableParameterCount(int count, boolean visible) {
5639
                            if (annotationRetention.isEnabled()) {
×
5640
                                super.visitAnnotableParameterCount(count, visible);
×
5641
                            }
5642
                        }
×
5643

5644
                        @Override
5645
                        @MaybeNull
5646
                        public AnnotationVisitor visitParameterAnnotation(int index, String descriptor, boolean visible) {
5647
                            return annotationRetention.isEnabled()
×
5648
                                    ? super.visitParameterAnnotation(index, descriptor, visible)
×
5649
                                    : IGNORE_ANNOTATION;
×
5650
                        }
5651

5652
                        @Override
5653
                        public void visitCode() {
5654
                            mv = IGNORE_METHOD;
×
5655
                        }
×
5656

5657
                        @Override
5658
                        public void visitEnd() {
5659
                            record.applyBody(actualMethodVisitor, implementationContext, annotationValueFilterFactory);
1✔
5660
                            actualMethodVisitor.visitEnd();
1✔
5661
                        }
1✔
5662
                    }
5663
                }
5664
            }
5665

5666
            /**
5667
             * A default type writer that only applies a type decoration.
5668
             *
5669
             * @param <V> The best known loaded type for the dynamically created type.
5670
             */
5671
            protected static class WithDecorationOnly<V> extends ForInlining<V> {
5672

5673
                /**
5674
                 * Creates a new inlining type writer that only applies a decoration.
5675
                 *
5676
                 * @param instrumentedType             The instrumented type to be created.
5677
                 * @param classFileVersion             The class file specified by the user.
5678
                 * @param auxiliaryTypes               The explicit auxiliary types to add to the created type.
5679
                 * @param methods                      The instrumented type's declared and virtually inherited methods.
5680
                 * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5681
                 * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5682
                 * @param annotationValueFilterFactory The annotation value filter factory to apply.
5683
                 * @param annotationRetention          The annotation retention to apply.
5684
                 * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5685
                 * @param implementationContextFactory The implementation context factory to apply.
5686
                 * @param typeValidation               Determines if a type should be explicitly validated.
5687
                 * @param classReaderFactory           The class reader factory to use.
5688
                 * @param classWriterFactory           The class writer factory to use.
5689
                 * @param typePool                     The type pool to use for computing stack map frames, if required.
5690
                 * @param classFileLocator             The class file locator for locating the original type's class file.
5691
                 */
5692
                protected WithDecorationOnly(TypeDescription instrumentedType,
5693
                                             ClassFileVersion classFileVersion,
5694
                                             List<? extends DynamicType> auxiliaryTypes,
5695
                                             MethodList<?> methods,
5696
                                             TypeAttributeAppender typeAttributeAppender,
5697
                                             AsmVisitorWrapper asmVisitorWrapper,
5698
                                             AnnotationValueFilter.Factory annotationValueFilterFactory,
5699
                                             AnnotationRetention annotationRetention,
5700
                                             AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5701
                                             Implementation.Context.Factory implementationContextFactory,
5702
                                             TypeValidation typeValidation,
5703
                                             AsmClassReader.Factory classReaderFactory,
5704
                                             AsmClassWriter.Factory classWriterFactory,
5705
                                             TypePool typePool,
5706
                                             ClassFileLocator classFileLocator) {
5707
                    super(instrumentedType,
1✔
5708
                            classFileVersion,
5709
                            FieldPool.Disabled.INSTANCE,
5710
                            RecordComponentPool.Disabled.INSTANCE,
5711
                            auxiliaryTypes,
5712
                            new LazyFieldList(instrumentedType),
5713
                            methods,
5714
                            new MethodList.Empty<MethodDescription>(),
5715
                            new RecordComponentList.Empty<RecordComponentDescription.InDefinedShape>(),
5716
                            LoadedTypeInitializer.NoOp.INSTANCE,
5717
                            TypeInitializer.None.INSTANCE,
5718
                            typeAttributeAppender,
5719
                            asmVisitorWrapper,
5720
                            annotationValueFilterFactory,
5721
                            annotationRetention,
5722
                            auxiliaryTypeNamingStrategy,
5723
                            implementationContextFactory,
5724
                            typeValidation,
5725
                            classReaderFactory,
5726
                            classWriterFactory,
5727
                            typePool,
5728
                            instrumentedType,
5729
                            classFileLocator);
5730
                }
1✔
5731

5732
                /**
5733
                 * {@inheritDoc}
5734
                 */
5735
                protected ClassVisitor writeTo(ClassVisitor classVisitor,
5736
                                               TypeInitializer typeInitializer,
5737
                                               ContextRegistry contextRegistry,
5738
                                               int writerFlags,
5739
                                               int readerFlags) {
5740
                    if (typeInitializer.isDefined()) {
1✔
5741
                        throw new UnsupportedOperationException("Cannot apply a type initializer for a decoration");
×
5742
                    }
5743
                    return new DecorationClassVisitor(classVisitor, contextRegistry, writerFlags, readerFlags);
1✔
5744
                }
5745

5746
                /**
5747
                 * A field list that only reads fields lazy to avoid an eager lookup since fields are often not required.
5748
                 */
5749
                protected static class LazyFieldList extends FieldList.AbstractBase<FieldDescription.InDefinedShape> {
5750

5751
                    /**
5752
                     * The instrumented type.
5753
                     */
5754
                    private final TypeDescription instrumentedType;
5755

5756
                    /**
5757
                     * Creates a lazy field list.
5758
                     *
5759
                     * @param instrumentedType The instrumented type.
5760
                     */
5761
                    protected LazyFieldList(TypeDescription instrumentedType) {
1✔
5762
                        this.instrumentedType = instrumentedType;
1✔
5763
                    }
1✔
5764

5765
                    /**
5766
                     * {@inheritDoc}
5767
                     */
5768
                    public FieldDescription.InDefinedShape get(int index) {
5769
                        return instrumentedType.getDeclaredFields().get(index);
×
5770
                    }
5771

5772
                    /**
5773
                     * {@inheritDoc}
5774
                     */
5775
                    public int size() {
5776
                        return instrumentedType.getDeclaredFields().size();
×
5777
                    }
5778
                }
5779

5780
                /**
5781
                 * A class visitor that decorates an existing type.
5782
                 */
5783
                @SuppressFBWarnings(value = "UWF_FIELD_NOT_INITIALIZED_IN_CONSTRUCTOR", justification = "Field access order is implied by ASM.")
5784
                protected class DecorationClassVisitor extends MetadataAwareClassVisitor implements TypeInitializer.Drain {
5785

5786
                    /**
5787
                     * A context registry to register the lazily created implementation context to.
5788
                     */
5789
                    private final ContextRegistry contextRegistry;
5790

5791
                    /**
5792
                     * The writer flags being used.
5793
                     */
5794
                    private final int writerFlags;
5795

5796
                    /**
5797
                     * The reader flags being used.
5798
                     */
5799
                    private final int readerFlags;
5800

5801
                    /**
5802
                     * The implementation context to use or {@code null} if the context is not yet initialized.
5803
                     */
5804
                    @UnknownNull
5805
                    private Implementation.Context.ExtractableView implementationContext;
5806

5807
                    /**
5808
                     * Creates a class visitor which is capable of decorating an existent class on the fly.
5809
                     *
5810
                     * @param classVisitor    The underlying class visitor to which writes are delegated.
5811
                     * @param contextRegistry A context registry to register the lazily created implementation context to.
5812
                     * @param writerFlags     The writer flags being used.
5813
                     * @param readerFlags     The reader flags being used.
5814
                     */
5815
                    protected DecorationClassVisitor(ClassVisitor classVisitor, ContextRegistry contextRegistry, int writerFlags, int readerFlags) {
1✔
5816
                        super(OpenedClassReader.ASM_API, classVisitor);
1✔
5817
                        this.contextRegistry = contextRegistry;
1✔
5818
                        this.writerFlags = writerFlags;
1✔
5819
                        this.readerFlags = readerFlags;
1✔
5820
                    }
1✔
5821

5822
                    @Override
5823
                    public void visit(int classFileVersionNumber,
5824
                                      int modifiers,
5825
                                      String internalName,
5826
                                      String genericSignature,
5827
                                      String superClassInternalName,
5828
                                      String[] interfaceTypeInternalName) {
5829
                        ClassFileVersion classFileVersion = ClassFileVersion.ofMinorMajor(classFileVersionNumber);
1✔
5830
                        implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5831
                                auxiliaryTypeNamingStrategy,
5832
                                typeInitializer,
5833
                                classFileVersion,
5834
                                WithDecorationOnly.this.classFileVersion,
5835
                                (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5836
                                        ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5837
                                        : Implementation.Context.FrameGeneration.DISABLED);
5838
                        contextRegistry.setImplementationContext(implementationContext);
1✔
5839
                        cv = asmVisitorWrapper.wrap(instrumentedType,
1✔
5840
                                cv,
5841
                                implementationContext,
5842
                                typePool,
5843
                                fields,
5844
                                methods,
5845
                                writerFlags,
5846
                                readerFlags);
5847
                        cv.visit(classFileVersionNumber, modifiers, internalName, genericSignature, superClassInternalName, interfaceTypeInternalName);
1✔
5848
                    }
1✔
5849

5850
                    @Override
5851
                    @MaybeNull
5852
                    protected AnnotationVisitor onVisitTypeAnnotation(int typeReference, TypePath typePath, String descriptor, boolean visible) {
5853
                        return annotationRetention.isEnabled()
×
5854
                                ? cv.visitTypeAnnotation(typeReference, typePath, descriptor, visible)
×
5855
                                : IGNORE_ANNOTATION;
×
5856
                    }
5857

5858
                    @Override
5859
                    @MaybeNull
5860
                    protected AnnotationVisitor onVisitAnnotation(String descriptor, boolean visible) {
5861
                        return annotationRetention.isEnabled()
1✔
5862
                                ? cv.visitAnnotation(descriptor, visible)
1✔
5863
                                : IGNORE_ANNOTATION;
1✔
5864
                    }
5865

5866
                    @Override
5867
                    protected void onAfterAttributes() {
5868
                        typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
5869
                    }
1✔
5870

5871
                    @Override
5872
                    protected void onVisitEnd() {
5873
                        implementationContext.drain(this, cv, annotationValueFilterFactory);
1✔
5874
                        cv.visitEnd();
1✔
5875
                    }
1✔
5876

5877
                    /**
5878
                     * {@inheritDoc}
5879
                     */
5880
                    public void apply(ClassVisitor classVisitor, TypeInitializer typeInitializer, Implementation.Context implementationContext) {
5881
                        /* do nothing */
5882
                    }
1✔
5883
                }
5884
            }
5885
        }
5886

5887
        /**
5888
         * A type writer that creates a class file that is not based upon another, existing class.
5889
         *
5890
         * @param <U> The best known loaded type for the dynamically created type.
5891
         */
5892
        @HashCodeAndEqualsPlugin.Enhance
5893
        public static class ForCreation<U> extends Default<U> {
5894

5895
            /**
5896
             * The method pool to use.
5897
             */
5898
            private final MethodPool methodPool;
5899

5900
            /**
5901
             * Creates a new default type writer for creating a new type that is not based on an existing class file.
5902
             *
5903
             * @param instrumentedType             The instrumented type to be created.
5904
             * @param classFileVersion             The class file version to write the instrumented type in and to apply when creating auxiliary types.
5905
             * @param fieldPool                    The field pool to use.
5906
             * @param methodPool                   The method pool to use.
5907
             * @param recordComponentPool          The record component pool to use.
5908
             * @param auxiliaryTypes               A list of auxiliary types to add to the created type.
5909
             * @param fields                       The instrumented type's declared fields.
5910
             * @param methods                      The instrumented type's declared and virtually inherited methods.
5911
             * @param instrumentedMethods          The instrumented methods relevant to this type creation.
5912
             * @param recordComponents             The instrumented type's record components.
5913
             * @param loadedTypeInitializer        The loaded type initializer to apply onto the created type after loading.
5914
             * @param typeInitializer              The type initializer to include in the created type's type initializer.
5915
             * @param typeAttributeAppender        The type attribute appender to apply onto the instrumented type.
5916
             * @param asmVisitorWrapper            The ASM visitor wrapper to apply onto the class writer.
5917
             * @param annotationValueFilterFactory The annotation value filter factory to apply.
5918
             * @param annotationRetention          The annotation retention to apply.
5919
             * @param auxiliaryTypeNamingStrategy  The naming strategy for auxiliary types to apply.
5920
             * @param implementationContextFactory The implementation context factory to apply.
5921
             * @param typeValidation               Determines if a type should be explicitly validated.
5922
             * @param classReaderFactory           The class reader factory to use.
5923
             * @param classWriterFactory           The class writer factory to use.
5924
             * @param typePool                     The type pool to use for computing stack map frames, if required.
5925
             */
5926
            protected ForCreation(TypeDescription instrumentedType,
5927
                                  ClassFileVersion classFileVersion,
5928
                                  FieldPool fieldPool,
5929
                                  MethodPool methodPool,
5930
                                  RecordComponentPool recordComponentPool,
5931
                                  List<? extends DynamicType> auxiliaryTypes,
5932
                                  FieldList<FieldDescription.InDefinedShape> fields,
5933
                                  MethodList<?> methods,
5934
                                  MethodList<?> instrumentedMethods,
5935
                                  RecordComponentList<RecordComponentDescription.InDefinedShape> recordComponents,
5936
                                  LoadedTypeInitializer loadedTypeInitializer,
5937
                                  TypeInitializer typeInitializer,
5938
                                  TypeAttributeAppender typeAttributeAppender,
5939
                                  AsmVisitorWrapper asmVisitorWrapper,
5940
                                  AnnotationValueFilter.Factory annotationValueFilterFactory,
5941
                                  AnnotationRetention annotationRetention,
5942
                                  AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
5943
                                  Implementation.Context.Factory implementationContextFactory,
5944
                                  TypeValidation typeValidation,
5945
                                  AsmClassReader.Factory classReaderFactory,
5946
                                  AsmClassWriter.Factory classWriterFactory,
5947
                                  TypePool typePool) {
5948
                super(instrumentedType,
1✔
5949
                        classFileVersion,
5950
                        fieldPool,
5951
                        recordComponentPool,
5952
                        auxiliaryTypes,
5953
                        fields,
5954
                        methods,
5955
                        instrumentedMethods,
5956
                        recordComponents,
5957
                        loadedTypeInitializer,
5958
                        typeInitializer,
5959
                        typeAttributeAppender,
5960
                        asmVisitorWrapper,
5961
                        annotationValueFilterFactory,
5962
                        annotationRetention,
5963
                        auxiliaryTypeNamingStrategy,
5964
                        implementationContextFactory,
5965
                        typeValidation,
5966
                        classReaderFactory,
5967
                        classWriterFactory,
5968
                        typePool);
5969
                this.methodPool = methodPool;
1✔
5970
            }
1✔
5971

5972
            /**
5973
             * {@inheritDoc}
5974
             */
5975
            public ContextClassVisitor wrap(ClassVisitor classVisitor, int writerFlags, int readerFlags) {
5976
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
5977
                        auxiliaryTypeNamingStrategy,
5978
                        typeInitializer,
5979
                        classFileVersion,
5980
                        classFileVersion,
5981
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
5982
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
5983
                                : Implementation.Context.FrameGeneration.DISABLED);
5984
                return new ImplementationContextClassVisitor(new CreationClassVisitor(asmVisitorWrapper.wrap(instrumentedType,
1✔
5985
                        ValidatingClassVisitor.of(classVisitor, typeValidation),
1✔
5986
                        implementationContext,
5987
                        typePool,
5988
                        fields,
5989
                        methods,
5990
                        asmVisitorWrapper.mergeWriter(writerFlags),
1✔
5991
                        asmVisitorWrapper.mergeReader(readerFlags)), implementationContext), implementationContext);
1✔
5992
            }
5993

5994
            @Override
5995
            @SuppressFBWarnings(value = "NP_NULL_ON_SOME_PATH_FROM_RETURN_VALUE", justification = "Relying on correlated type properties.")
5996
            protected UnresolvedType create(TypeInitializer typeInitializer, ClassDumpAction.Dispatcher dispatcher) {
5997
                int writerFlags = asmVisitorWrapper.mergeWriter(AsmVisitorWrapper.NO_FLAGS), readerFlags = asmVisitorWrapper.mergeReader(AsmVisitorWrapper.NO_FLAGS);
1✔
5998
                AsmClassWriter classWriter = classWriterFactory.make(writerFlags, typePool);
1✔
5999
                Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType,
1✔
6000
                        auxiliaryTypeNamingStrategy,
6001
                        typeInitializer,
6002
                        classFileVersion,
6003
                        classFileVersion,
6004
                        (writerFlags & ClassWriter.COMPUTE_FRAMES) == 0 && classFileVersion.isAtLeast(ClassFileVersion.JAVA_V6)
1✔
6005
                                ? ((readerFlags & ClassReader.EXPAND_FRAMES) == 0 ? Implementation.Context.FrameGeneration.GENERATE : Implementation.Context.FrameGeneration.EXPAND)
6006
                                : Implementation.Context.FrameGeneration.DISABLED);
6007
                ClassVisitor classVisitor = asmVisitorWrapper.wrap(instrumentedType,
1✔
6008
                        ValidatingClassVisitor.of(classWriter.getVisitor(), typeValidation),
1✔
6009
                        implementationContext,
6010
                        typePool,
6011
                        fields,
6012
                        methods,
6013
                        writerFlags,
6014
                        readerFlags);
6015
                classVisitor.visit(classFileVersion.getMinorMajorVersion(),
1✔
6016
                        instrumentedType.getActualModifiers(!instrumentedType.isInterface()),
1✔
6017
                        instrumentedType.getInternalName(),
1✔
6018
                        instrumentedType.getGenericSignature(),
1✔
6019
                        (instrumentedType.getSuperClass() == null
1✔
6020
                                ? TypeDescription.ForLoadedType.of(Object.class)
1✔
6021
                                : instrumentedType.getSuperClass().asErasure()).getInternalName(),
1✔
6022
                        instrumentedType.getInterfaces().asErasures().toInternalNames());
1✔
6023
                if (!instrumentedType.isNestHost()) {
1✔
6024
                    classVisitor.visitNestHost(instrumentedType.getNestHost().getInternalName());
×
6025
                }
6026
                MethodDescription.InDefinedShape enclosingMethod = instrumentedType.getEnclosingMethod();
1✔
6027
                if (enclosingMethod != null) {
1✔
6028
                    classVisitor.visitOuterClass(enclosingMethod.getDeclaringType().getInternalName(),
1✔
6029
                            enclosingMethod.getInternalName(),
1✔
6030
                            enclosingMethod.getDescriptor());
1✔
6031
                } else if (instrumentedType.isLocalType() || instrumentedType.isAnonymousType()) {
1✔
6032
                    classVisitor.visitOuterClass(instrumentedType.getEnclosingType().getInternalName(), NO_REFERENCE, NO_REFERENCE);
1✔
6033
                }
6034
                typeAttributeAppender.apply(classVisitor, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6035
                if (instrumentedType.isNestHost()) {
1✔
6036
                    for (TypeDescription typeDescription : instrumentedType.getNestMembers().filter(not(is(instrumentedType)))) {
1✔
6037
                        classVisitor.visitNestMember(typeDescription.getInternalName());
×
6038
                    }
×
6039
                }
6040
                for (TypeDescription typeDescription : instrumentedType.getPermittedSubtypes()) {
1✔
6041
                    classVisitor.visitPermittedSubclass(typeDescription.getInternalName());
×
6042
                }
×
6043
                TypeDescription declaringType = instrumentedType.getDeclaringType();
1✔
6044
                if (declaringType != null) {
1✔
6045
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6046
                            declaringType.getInternalName(),
1✔
6047
                            instrumentedType.getSimpleName(),
1✔
6048
                            instrumentedType.getModifiers());
1✔
6049
                } else if (instrumentedType.isLocalType()) {
1✔
6050
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6051
                            NO_REFERENCE,
1✔
6052
                            instrumentedType.getSimpleName(),
1✔
6053
                            instrumentedType.getModifiers());
1✔
6054
                } else if (instrumentedType.isAnonymousType()) {
1✔
6055
                    classVisitor.visitInnerClass(instrumentedType.getInternalName(),
1✔
6056
                            NO_REFERENCE,
1✔
6057
                            NO_REFERENCE,
1✔
6058
                            instrumentedType.getModifiers());
1✔
6059
                }
6060
                for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6061
                    classVisitor.visitInnerClass(typeDescription.getInternalName(),
1✔
6062
                            typeDescription.isMemberType()
1✔
6063
                                    ? instrumentedType.getInternalName()
1✔
6064
                                    : NO_REFERENCE,
1✔
6065
                            typeDescription.isAnonymousType()
1✔
6066
                                    ? NO_REFERENCE
1✔
6067
                                    : typeDescription.getSimpleName(),
1✔
6068
                            typeDescription.getModifiers());
1✔
6069
                }
1✔
6070
                for (RecordComponentDescription recordComponentDescription : recordComponents) {
1✔
6071
                    recordComponentPool.target(recordComponentDescription).apply(classVisitor, annotationValueFilterFactory);
×
6072
                }
×
6073
                for (FieldDescription fieldDescription : fields) {
1✔
6074
                    fieldPool.target(fieldDescription).apply(classVisitor, annotationValueFilterFactory);
1✔
6075
                }
1✔
6076
                for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6077
                    methodPool.target(methodDescription).apply(classVisitor, implementationContext, annotationValueFilterFactory);
1✔
6078
                }
1✔
6079
                implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6080
                        methodPool,
6081
                        annotationValueFilterFactory), classVisitor, annotationValueFilterFactory);
6082
                classVisitor.visitEnd();
1✔
6083
                return new UnresolvedType(classWriter.getBinaryRepresentation(), implementationContext.getAuxiliaryTypes());
1✔
6084
            }
6085

6086
            /**
6087
             * A class visitor that applies the subclass creation as a wrapper.
6088
             */
6089
            protected class CreationClassVisitor extends MetadataAwareClassVisitor {
6090

6091
                /**
6092
                 * The implementation context to apply.
6093
                 */
6094
                private final Implementation.Context.ExtractableView implementationContext;
6095

6096
                /**
6097
                 * The declared types that have been visited.
6098
                 */
6099
                private final Set<String> declaredTypes = new HashSet<String>();
1✔
6100

6101
                /**
6102
                 * The signatures of all fields that were explicitly visited.
6103
                 */
6104
                private final Set<SignatureKey> visitedFields = new HashSet<SignatureKey>();
1✔
6105

6106
                /**
6107
                 * The signature of all methods that were explicitly visited.
6108
                 */
6109
                private final Set<SignatureKey> visitedMethods = new HashSet<SignatureKey>();
1✔
6110

6111
                /**
6112
                 * Creates a new wrapper visitor.
6113
                 *
6114
                 * @param classVisitor          The class visitor being wrapped.
6115
                 * @param implementationContext The implementation context to apply.
6116
                 */
6117
                protected CreationClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6118
                    super(OpenedClassReader.ASM_API, classVisitor);
1✔
6119
                    this.implementationContext = implementationContext;
1✔
6120
                }
1✔
6121

6122
                @Override
6123
                protected void onAfterAttributes() {
6124
                    typeAttributeAppender.apply(cv, instrumentedType, annotationValueFilterFactory.on(instrumentedType));
1✔
6125
                }
1✔
6126

6127
                @Override
6128
                protected void onVisitInnerClass(String internalName, @MaybeNull String outerName, @MaybeNull String innerName, int modifiers) {
6129
                    declaredTypes.add(internalName);
×
6130
                    super.onVisitInnerClass(internalName, outerName, innerName, modifiers);
×
6131
                }
×
6132

6133
                @Override
6134
                protected FieldVisitor onVisitField(int modifiers, String name, String descriptor, @MaybeNull String signature, @MaybeNull Object value) {
6135
                    visitedFields.add(new SignatureKey(name, descriptor));
×
6136
                    return super.onVisitField(modifiers, name, descriptor, signature, value);
×
6137
                }
6138

6139
                @Override
6140
                protected MethodVisitor onVisitMethod(int modifiers, String internalName, String descriptor, @MaybeNull String signature, @MaybeNull String[] exception) {
6141
                    visitedMethods.add(new SignatureKey(internalName, descriptor));
×
6142
                    return super.onVisitMethod(modifiers, internalName, descriptor, signature, exception);
×
6143
                }
6144

6145
                @Override
6146
                protected void onVisitEnd() {
6147
                    for (TypeDescription typeDescription : instrumentedType.getDeclaredTypes()) {
1✔
6148
                        if (!declaredTypes.contains(typeDescription.getInternalName())) {
×
6149
                            cv.visitInnerClass(typeDescription.getInternalName(),
×
6150
                                    typeDescription.isMemberType()
×
6151
                                            ? instrumentedType.getInternalName()
×
6152
                                            : NO_REFERENCE,
×
6153
                                    typeDescription.isAnonymousType()
×
6154
                                            ? NO_REFERENCE
×
6155
                                            : typeDescription.getSimpleName(),
×
6156
                                    typeDescription.getModifiers());
×
6157
                        }
6158
                    }
×
6159
                    for (FieldDescription fieldDescription : fields) {
1✔
6160
                        if (!visitedFields.contains(new SignatureKey(fieldDescription.getName(), fieldDescription.getDescriptor()))) {
×
6161
                            fieldPool.target(fieldDescription).apply(cv, annotationValueFilterFactory);
×
6162
                        }
6163
                    }
×
6164
                    for (MethodDescription methodDescription : instrumentedMethods) {
1✔
6165
                        if (!visitedMethods.contains(new SignatureKey(methodDescription.getInternalName(), methodDescription.getDescriptor()))) {
1✔
6166
                            methodPool.target(methodDescription).apply(cv, implementationContext, annotationValueFilterFactory);
1✔
6167
                        }
6168
                    }
1✔
6169
                    implementationContext.drain(new TypeInitializer.Drain.Default(instrumentedType,
1✔
6170
                            methodPool,
1✔
6171
                            annotationValueFilterFactory), cv, annotationValueFilterFactory);
6172
                    super.onVisitEnd();
1✔
6173
                }
1✔
6174
            }
6175

6176
            /**
6177
             * A context class visitor based on an {@link Implementation.Context}.
6178
             */
6179
            protected class ImplementationContextClassVisitor extends ContextClassVisitor {
6180

6181
                /**
6182
                 * The implementation context to use.
6183
                 */
6184
                private final Implementation.Context.ExtractableView implementationContext;
6185

6186
                /**
6187
                 * Creates a context class loader based on an {@link Implementation.Context}.
6188
                 *
6189
                 * @param classVisitor          The class visitor to delegate to.
6190
                 * @param implementationContext The implementation context to use.
6191
                 */
6192
                protected ImplementationContextClassVisitor(ClassVisitor classVisitor, Implementation.Context.ExtractableView implementationContext) {
1✔
6193
                    super(classVisitor);
1✔
6194
                    this.implementationContext = implementationContext;
1✔
6195
                }
1✔
6196

6197
                @Override
6198
                public List<DynamicType> getAuxiliaryTypes() {
6199
                    return CompoundList.of(auxiliaryTypes, implementationContext.getAuxiliaryTypes());
1✔
6200
                }
6201

6202
                @Override
6203
                public LoadedTypeInitializer getLoadedTypeInitializer() {
6204
                    return loadedTypeInitializer;
1✔
6205
                }
6206
            }
6207
        }
6208

6209
        /**
6210
         * An action to write a class file to the dumping location.
6211
         */
6212
        @HashCodeAndEqualsPlugin.Enhance
6213
        protected static class ClassDumpAction implements PrivilegedExceptionAction<Void> {
6214

6215
            /**
6216
             * Indicates that nothing is returned from this action.
6217
             */
6218
            @AlwaysNull
6219
            private static final Void NOTHING = null;
1✔
6220

6221
            /**
6222
             * The target folder for writing the class file to.
6223
             */
6224
            private final String target;
6225

6226
            /**
6227
             * The instrumented type.
6228
             */
6229
            private final TypeDescription instrumentedType;
6230

6231
            /**
6232
             * {@code true} if the dumped class file is an input to a class transformation.
6233
             */
6234
            private final boolean original;
6235

6236
            /**
6237
             * The suffix to append to the dumped class file.
6238
             */
6239
            private final long suffix;
6240

6241
            /**
6242
             * The type's binary representation.
6243
             */
6244
            private final byte[] binaryRepresentation;
6245

6246
            /**
6247
             * Creates a new class dump action.
6248
             *
6249
             * @param target               The target folder for writing the class file to.
6250
             * @param instrumentedType     The instrumented type.
6251
             * @param original             {@code true} if the dumped class file is an input to a class transformation.
6252
             * @param suffix               The suffix to append to the dumped class file.
6253
             * @param binaryRepresentation The type's binary representation.
6254
             */
6255
            protected ClassDumpAction(String target, TypeDescription instrumentedType, boolean original, long suffix, byte[] binaryRepresentation) {
1✔
6256
                this.target = target;
1✔
6257
                this.instrumentedType = instrumentedType;
1✔
6258
                this.original = original;
1✔
6259
                this.suffix = suffix;
1✔
6260
                this.binaryRepresentation = binaryRepresentation;
1✔
6261
            }
1✔
6262

6263
            /**
6264
             * {@inheritDoc}
6265
             */
6266
            public Void run() throws Exception {
6267
                OutputStream outputStream = new FileOutputStream(new File(target, instrumentedType.getName()
1✔
6268
                        + (original ? "-original." : ".")
6269
                        + suffix
6270
                        + ".class"));
6271
                try {
6272
                    outputStream.write(binaryRepresentation);
1✔
6273
                    return NOTHING;
1✔
6274
                } finally {
6275
                    outputStream.close();
1✔
6276
                }
1✔
6277
            }
6278

6279
            /**
6280
             * A dispatcher for dumping class files to the file system.
6281
             */
6282
            protected interface Dispatcher {
6283

6284
                /**
6285
                 * Dumps a class file to the file system.
6286
                 *
6287
                 * @param instrumentedType     The type to dump.
6288
                 * @param original             {@code true} if the class file is in its original state.
6289
                 * @param binaryRepresentation The class file's binary representation.
6290
                 */
6291
                void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation);
6292

6293
                /**
6294
                 * A disabled dispatcher that does not dump any class files.
6295
                 */
6296
                enum Disabled implements Dispatcher {
1✔
6297

6298
                    /**
6299
                     * The singleton instance.
6300
                     */
6301
                    INSTANCE;
1✔
6302

6303
                    /**
6304
                     * {@inheritDoc}
6305
                     */
6306
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6307
                        /* do nothing */
6308
                    }
1✔
6309
                }
6310

6311
                /**
6312
                 * An enabled dispatcher that dumps class files to a given folder.
6313
                 */
6314
                @HashCodeAndEqualsPlugin.Enhance
6315
                class Enabled implements Dispatcher {
6316

6317
                    /**
6318
                     * The folder to write class files to.
6319
                     */
6320
                    private final String folder;
6321

6322
                    /**
6323
                     * The timestamp to append.
6324
                     */
6325
                    private final long timestamp;
6326

6327
                    /**
6328
                     * Creates a new dispatcher for dumping class files.
6329
                     *
6330
                     * @param folder    The folder to write class files to.
6331
                     * @param timestamp The timestamp to append.
6332
                     */
6333
                    protected Enabled(String folder, long timestamp) {
1✔
6334
                        this.folder = folder;
1✔
6335
                        this.timestamp = timestamp;
1✔
6336
                    }
1✔
6337

6338
                    /**
6339
                     * {@inheritDoc}
6340
                     */
6341
                    public void dump(TypeDescription instrumentedType, boolean original, byte[] binaryRepresentation) {
6342
                        try {
6343
                            doPrivileged(new ClassDumpAction(folder, instrumentedType, original, timestamp, binaryRepresentation));
1✔
6344
                        } catch (Exception exception) {
×
6345
                            exception.printStackTrace();
×
6346
                        }
1✔
6347
                    }
1✔
6348
                }
6349
            }
6350
        }
6351
    }
6352
}
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

© 2025 Coveralls, Inc