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

raphw / byte-buddy / #809

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

push

raphw
Clean up code.

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

958 existing lines in 10 files now uncovered.

29803 of 35465 relevant lines covered (84.03%)

0.84 hits per line

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

70.14
/byte-buddy-dep/src/main/java/net/bytebuddy/ByteBuddy.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;
17

18
import net.bytebuddy.build.AccessControllerPlugin;
19
import net.bytebuddy.build.HashCodeAndEqualsPlugin;
20
import net.bytebuddy.description.annotation.AnnotationDescription;
21
import net.bytebuddy.description.annotation.AnnotationValue;
22
import net.bytebuddy.description.field.FieldDescription;
23
import net.bytebuddy.description.method.MethodDescription;
24
import net.bytebuddy.description.method.ParameterDescription;
25
import net.bytebuddy.description.modifier.EnumerationState;
26
import net.bytebuddy.description.modifier.ModifierContributor;
27
import net.bytebuddy.description.modifier.Ownership;
28
import net.bytebuddy.description.modifier.TypeManifestation;
29
import net.bytebuddy.description.modifier.Visibility;
30
import net.bytebuddy.description.module.ModuleDescription;
31
import net.bytebuddy.description.type.PackageDescription;
32
import net.bytebuddy.description.type.RecordComponentDescription;
33
import net.bytebuddy.description.type.TypeDefinition;
34
import net.bytebuddy.description.type.TypeDescription;
35
import net.bytebuddy.description.type.TypeList;
36
import net.bytebuddy.description.type.TypeVariableToken;
37
import net.bytebuddy.dynamic.ClassFileLocator;
38
import net.bytebuddy.dynamic.DynamicType;
39
import net.bytebuddy.dynamic.TargetType;
40
import net.bytebuddy.dynamic.Transformer;
41
import net.bytebuddy.dynamic.VisibilityBridgeStrategy;
42
import net.bytebuddy.dynamic.scaffold.InstrumentedType;
43
import net.bytebuddy.dynamic.scaffold.MethodGraph;
44
import net.bytebuddy.dynamic.scaffold.MethodRegistry;
45
import net.bytebuddy.dynamic.scaffold.TypeValidation;
46
import net.bytebuddy.dynamic.scaffold.inline.DecoratingDynamicTypeBuilder;
47
import net.bytebuddy.dynamic.scaffold.inline.MethodNameTransformer;
48
import net.bytebuddy.dynamic.scaffold.inline.RebaseDynamicTypeBuilder;
49
import net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder;
50
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
51
import net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder;
52
import net.bytebuddy.implementation.Implementation;
53
import net.bytebuddy.implementation.MethodCall;
54
import net.bytebuddy.implementation.SuperMethodCall;
55
import net.bytebuddy.implementation.attribute.AnnotationRetention;
56
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
57
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
58
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
59
import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
60
import net.bytebuddy.implementation.bytecode.Duplication;
61
import net.bytebuddy.implementation.bytecode.StackManipulation;
62
import net.bytebuddy.implementation.bytecode.TypeCreation;
63
import net.bytebuddy.implementation.bytecode.assign.Assigner;
64
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
65
import net.bytebuddy.implementation.bytecode.collection.ArrayFactory;
66
import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
67
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
68
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
69
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
70
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
71
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
72
import net.bytebuddy.matcher.ElementMatcher;
73
import net.bytebuddy.matcher.LatentMatcher;
74
import net.bytebuddy.utility.AsmClassReader;
75
import net.bytebuddy.utility.AsmClassWriter;
76
import net.bytebuddy.utility.CompoundList;
77
import net.bytebuddy.utility.GraalImageCode;
78
import net.bytebuddy.utility.JavaConstant;
79
import net.bytebuddy.utility.JavaType;
80
import net.bytebuddy.utility.RandomString;
81
import net.bytebuddy.utility.nullability.MaybeNull;
82
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
83
import org.objectweb.asm.MethodVisitor;
84
import org.objectweb.asm.Opcodes;
85

86
import java.lang.annotation.Annotation;
87
import java.lang.annotation.ElementType;
88
import java.lang.reflect.Type;
89
import java.security.PrivilegedAction;
90
import java.util.ArrayList;
91
import java.util.Arrays;
92
import java.util.Collection;
93
import java.util.Collections;
94
import java.util.List;
95
import java.util.Random;
96

97
import static net.bytebuddy.matcher.ElementMatchers.isConstructor;
98
import static net.bytebuddy.matcher.ElementMatchers.isDefaultFinalizer;
99
import static net.bytebuddy.matcher.ElementMatchers.isEquals;
100
import static net.bytebuddy.matcher.ElementMatchers.isHashCode;
101
import static net.bytebuddy.matcher.ElementMatchers.isSynthetic;
102
import static net.bytebuddy.matcher.ElementMatchers.isToString;
103
import static net.bytebuddy.matcher.ElementMatchers.named;
104
import static net.bytebuddy.matcher.ElementMatchers.takesArguments;
105
import static net.bytebuddy.matcher.ElementMatchers.takesGenericArguments;
106
import static net.bytebuddy.matcher.ElementMatchers.targetsElement;
107

108
/**
109
 * Instances of this class serve as a focus point for configuration of the library's behavior and as an entry point
110
 * to any form of code generation using the library. For this purpose, Byte Buddy offers a fluent API which allows
111
 * for the step-wise generation of a new Java type. A type is generated either by:
112
 * <ul>
113
 * <li><b>Subclassing</b> some type: A subclass - as the name suggests - extends another, existing Java type. Virtual
114
 * members of the generated type's super types can be overridden. Subclasses can also be interface extensions of one
115
 * or several interfaces.</li>
116
 * <li><b>Redefining</b> a type: By redefining a type, it is not only possible to override virtual methods of the
117
 * redefined type but also to redefine existing methods. This way, it is also possible to change the behavior of
118
 * non-virtual methods and constructors of the redefined type.</li>
119
 * <li><b>Rebasing</b> a type: Rebasing a type works similar to creating a subclass, i.e. any method being overridden
120
 * is still capable of invoking any original code of the rebased type. Any rebased method is however inlined into the
121
 * rebased type and any original code is preserved automatically. This way, the type's identity does not change.</li>
122
 * </ul>
123
 * Byte Buddy's API does not change when a type is rebased, redefined or subclassed. All types are created via the
124
 * {@link net.bytebuddy.dynamic.DynamicType.Builder} interface. Byte Buddy's API is expressed by fully immutable
125
 * components and is therefore thread-safe. As a consequence, method calls must be chained for all of Byte Buddy's
126
 * component, e.g. a method call like the following has no effect:
127
 * <pre>
128
 * ByteBuddy byteBuddy = new ByteBuddy();
129
 * byteBuddy.foo()</pre>
130
 * Instead, the following method chain is correct use of the API:
131
 * <pre>
132
 * ByteBuddy byteBuddy = new ByteBuddy().foo();</pre>
133
 * <p>
134
 * For the creation of Java agents, Byte Buddy offers a convenience API implemented by the
135
 * {@link net.bytebuddy.agent.builder.AgentBuilder}. The API wraps a {@link ByteBuddy} instance and offers agent-specific
136
 * configuration opportunities by integrating against the {@link java.lang.instrument.Instrumentation} API.
137
 * </p>
138
 *
139
 * @see net.bytebuddy.agent.builder.AgentBuilder
140
 */
141
@HashCodeAndEqualsPlugin.Enhance
142
public class ByteBuddy {
143

144
    /**
145
     * A property that controls the default naming strategy. If not set, Byte Buddy is generating
146
     * random names for types that are not named explicitly. If set to {@code fixed}, Byte Buddy is
147
     * setting names deterministically without any random element, or to {@code caller}, if a name
148
     * should be fixed but contain the name of the caller class and method. If set to a numeric
149
     * value, Byte Buddy is generating random names, using the number as a seed.
150
     */
151
    public static final String DEFAULT_NAMING_PROPERTY = "net.bytebuddy.naming";
152

153
    /**
154
     * A property that controls the default type validation applied by Byte Buddy. If not set,
155
     * and if not otherwise configured by the user, types will be explicitly validated to
156
     * supply better error messages.
157
     */
158
    public static final String DEFAULT_VALIDATION_PROPERTY = "net.bytebuddy.validation";
159

160
    /**
161
     * The default prefix for the default {@link net.bytebuddy.NamingStrategy}.
162
     */
163
    private static final String BYTE_BUDDY_DEFAULT_PREFIX = "ByteBuddy";
164

165
    /**
166
     * The default suffix when defining a {@link AuxiliaryType.NamingStrategy}.
167
     */
168
    private static final String BYTE_BUDDY_DEFAULT_SUFFIX = "auxiliary";
169

170
    /**
171
     * The default name of a fixed context name for synthetic fields and methods.
172
     */
173
    private static final String BYTE_BUDDY_DEFAULT_CONTEXT_NAME = "synthetic";
174

175
    /**
176
     * The default type validation to apply.
177
     */
178
    private static final TypeValidation DEFAULT_TYPE_VALIDATION;
179

180
    /**
181
     * The default naming strategy or {@code null} if no such strategy is set.
182
     */
183
    @MaybeNull
184
    private static final NamingStrategy DEFAULT_NAMING_STRATEGY;
185

186
    /**
187
     * The default auxiliary naming strategy or {@code null} if no such strategy is set.
188
     */
189
    @MaybeNull
190
    private static final AuxiliaryType.NamingStrategy DEFAULT_AUXILIARY_NAMING_STRATEGY;
191

192
    /**
193
     * The default implementation context factory or {@code null} if no such factory is set.
194
     */
195
    @MaybeNull
196
    private static final Implementation.Context.Factory DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY;
197

198
    /*
199
     * Resolves the default naming strategy.
200
     */
201
    static {
202
        String validation;
203
        try {
204
            validation = doPrivileged(new GetSystemPropertyAction(DEFAULT_VALIDATION_PROPERTY));
1✔
205
        } catch (Throwable ignored) {
×
UNCOV
206
            validation = null;
×
207
        }
1✔
208
        DEFAULT_TYPE_VALIDATION = validation == null || Boolean.parseBoolean(validation)
1✔
209
                ? TypeValidation.ENABLED
210
                : TypeValidation.DISABLED;
211
        String naming;
212
        try {
213
            naming = doPrivileged(new GetSystemPropertyAction(DEFAULT_NAMING_PROPERTY));
1✔
214
        } catch (Throwable ignored) {
×
UNCOV
215
            naming = null;
×
216
        }
1✔
217
        NamingStrategy namingStrategy;
218
        AuxiliaryType.NamingStrategy auxiliaryNamingStrategy;
219
        Implementation.Context.Factory implementationContextFactory;
220
        if (naming == null) {
1✔
221
            if (GraalImageCode.getCurrent().isDefined()) {
1✔
UNCOV
222
                namingStrategy = new NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_PREFIX,
×
223
                        new NamingStrategy.Suffixing.BaseNameResolver.WithCallerSuffix(NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE),
224
                        NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE);
225
                auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
UNCOV
226
                implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
227
            } else {
228
                namingStrategy = null;
1✔
229
                auxiliaryNamingStrategy = null;
1✔
230
                implementationContextFactory = null;
1✔
231
            }
232
        } else if (naming.equalsIgnoreCase("fixed")) {
×
UNCOV
233
            namingStrategy = new NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_PREFIX,
×
234
                    NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE,
235
                    NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE);
236
            auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
237
            implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
238
        } else if (naming.equalsIgnoreCase("caller")) {
×
UNCOV
239
            namingStrategy = new NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_PREFIX,
×
240
                    new NamingStrategy.Suffixing.BaseNameResolver.WithCallerSuffix(NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE),
241
                    NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE);
242
            auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
UNCOV
243
            implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
244
        } else {
245
            long seed;
246
            try {
247
                seed = Long.parseLong(naming);
×
248
            } catch (Exception ignored) {
×
249
                throw new IllegalStateException("'net.bytebuddy.naming' is set to an unknown, non-numeric value: " + naming);
×
250
            }
×
UNCOV
251
            namingStrategy = new NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_PREFIX,
×
252
                    NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE,
253
                    NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE,
254
                    new RandomString(RandomString.DEFAULT_LENGTH, new Random(seed)));
255
            auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
UNCOV
256
            implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
257
        }
258
        DEFAULT_NAMING_STRATEGY = namingStrategy;
1✔
259
        DEFAULT_AUXILIARY_NAMING_STRATEGY = auxiliaryNamingStrategy;
1✔
260
        DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY = implementationContextFactory;
1✔
261
    }
1✔
262

263
    /**
264
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
265
     *
266
     * @param action The action to execute from a privileged context.
267
     * @param <T>    The type of the action's resolved value.
268
     * @return The action's resolved value.
269
     */
270
    @MaybeNull
271
    @AccessControllerPlugin.Enhance
272
    private static <T> T doPrivileged(PrivilegedAction<T> action) {
UNCOV
273
        return action.run();
×
274
    }
275

276
    /**
277
     * The class file version to use for types that are not based on an existing class file.
278
     */
279
    protected final ClassFileVersion classFileVersion;
280

281
    /**
282
     * The naming strategy to use.
283
     */
284
    protected final NamingStrategy namingStrategy;
285

286
    /**
287
     * The naming strategy to use for naming auxiliary types.
288
     */
289
    protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
290

291
    /**
292
     * The annotation value filter factory to use.
293
     */
294
    protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
295

296
    /**
297
     * The annotation retention strategy to use.
298
     */
299
    protected final AnnotationRetention annotationRetention;
300

301
    /**
302
     * The implementation context factory to use.
303
     */
304
    protected final Implementation.Context.Factory implementationContextFactory;
305

306
    /**
307
     * The method graph compiler to use.
308
     */
309
    protected final MethodGraph.Compiler methodGraphCompiler;
310

311
    /**
312
     * The instrumented type factory to use.
313
     */
314
    protected final InstrumentedType.Factory instrumentedTypeFactory;
315

316
    /**
317
     * A matcher for identifying methods that should be excluded from instrumentation.
318
     */
319
    protected final LatentMatcher<? super MethodDescription> ignoredMethods;
320

321
    /**
322
     * Determines if a type should be explicitly validated.
323
     */
324
    protected final TypeValidation typeValidation;
325

326
    /**
327
     * The visibility bridge strategy to apply.
328
     */
329
    protected final VisibilityBridgeStrategy visibilityBridgeStrategy;
330

331
    /**
332
     * The class reader factory to use.
333
     */
334
    protected final AsmClassReader.Factory classReaderFactory;
335

336
    /**
337
     * The class writer factory to use.
338
     */
339
    protected final AsmClassWriter.Factory classWriterFactory;
340

341
    /**
342
     * <p>
343
     * Creates a new Byte Buddy instance with a default configuration that is suitable for most use cases.
344
     * </p>
345
     * <p>
346
     * When creating this configuration, Byte Buddy attempts to discover the current JVM's version. If this
347
     * is not possible, class files are created Java 6-compatible.
348
     * </p>
349
     *
350
     * @see ClassFileVersion#ofThisVm(ClassFileVersion)
351
     */
352
    public ByteBuddy() {
353
        this(ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5));
1✔
354
    }
1✔
355

356
    /**
357
     * Creates a new Byte Buddy instance with a default configuration that is suitable for most use cases.
358
     *
359
     * @param classFileVersion The class file version to use for types that are not based on an existing class file.
360
     */
361
    public ByteBuddy(ClassFileVersion classFileVersion) {
362
        this(classFileVersion,
1✔
363
                DEFAULT_NAMING_STRATEGY == null
364
                        ? new NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_PREFIX)
365
                        : DEFAULT_NAMING_STRATEGY,
366
                DEFAULT_AUXILIARY_NAMING_STRATEGY == null
367
                        ? new AuxiliaryType.NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_SUFFIX)
368
                        : DEFAULT_AUXILIARY_NAMING_STRATEGY,
369
                AnnotationValueFilter.Default.APPEND_DEFAULTS,
370
                AnnotationRetention.ENABLED,
371
                DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY == null
372
                        ? Implementation.Context.Default.Factory.INSTANCE
373
                        : DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY,
374
                MethodGraph.Compiler.DEFAULT,
375
                InstrumentedType.Factory.Default.MODIFIABLE,
376
                DEFAULT_TYPE_VALIDATION,
377
                VisibilityBridgeStrategy.Default.ALWAYS,
378
                AsmClassReader.Factory.Default.IMPLICIT,
379
                AsmClassWriter.Factory.Default.IMPLICIT,
380
                new LatentMatcher.Resolved<MethodDescription>(isSynthetic().or(isDefaultFinalizer())));
1✔
381
    }
1✔
382

383
    /**
384
     * Creates a new Byte Buddy instance.
385
     *
386
     * @param classFileVersion             The class file version to use for types that are not based on an existing class file.
387
     * @param namingStrategy               The naming strategy to use.
388
     * @param auxiliaryTypeNamingStrategy  The naming strategy to use for naming auxiliary types.
389
     * @param annotationValueFilterFactory The annotation value filter factory to use.
390
     * @param annotationRetention          The annotation retention strategy to use.
391
     * @param implementationContextFactory The implementation context factory to use.
392
     * @param methodGraphCompiler          The method graph compiler to use.
393
     * @param instrumentedTypeFactory      The instrumented type factory to use.
394
     * @param typeValidation               Determines if a type should be explicitly validated.
395
     * @param visibilityBridgeStrategy     The visibility bridge strategy to apply.
396
     * @param classReaderFactory           The class reader factory to use.
397
     * @param classWriterFactory           The class writer factory to use.
398
     * @param ignoredMethods               A matcher for identifying methods that should be excluded from instrumentation.
399
     */
400
    protected ByteBuddy(ClassFileVersion classFileVersion,
401
                        NamingStrategy namingStrategy,
402
                        AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
403
                        AnnotationValueFilter.Factory annotationValueFilterFactory,
404
                        AnnotationRetention annotationRetention,
405
                        Implementation.Context.Factory implementationContextFactory,
406
                        MethodGraph.Compiler methodGraphCompiler,
407
                        InstrumentedType.Factory instrumentedTypeFactory,
408
                        TypeValidation typeValidation,
409
                        VisibilityBridgeStrategy visibilityBridgeStrategy,
410
                        AsmClassReader.Factory classReaderFactory,
411
                        AsmClassWriter.Factory classWriterFactory,
412
                        LatentMatcher<? super MethodDescription> ignoredMethods) {
1✔
413
        this.classFileVersion = classFileVersion;
1✔
414
        this.namingStrategy = namingStrategy;
1✔
415
        this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
416
        this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
417
        this.annotationRetention = annotationRetention;
1✔
418
        this.implementationContextFactory = implementationContextFactory;
1✔
419
        this.methodGraphCompiler = methodGraphCompiler;
1✔
420
        this.instrumentedTypeFactory = instrumentedTypeFactory;
1✔
421
        this.typeValidation = typeValidation;
1✔
422
        this.visibilityBridgeStrategy = visibilityBridgeStrategy;
1✔
423
        this.classReaderFactory = classReaderFactory;
1✔
424
        this.classWriterFactory = classWriterFactory;
1✔
425
        this.ignoredMethods = ignoredMethods;
1✔
426
    }
1✔
427

428
    /**
429
     * <p>
430
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
431
     * this interface type is created.
432
     * </p>
433
     * <p>
434
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type. Any constructor is implemented
435
     * to only invoke its super type constructor of equal signature. Another behavior can be specified by supplying an explicit
436
     * {@link ConstructorStrategy} by {@link ByteBuddy#subclass(Class, ConstructorStrategy)}.
437
     * </p>
438
     * <p>
439
     * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
440
     * </p>
441
     * <p>
442
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
443
     * types, a external cache or {@link TypeCache} should be used.
444
     * </p>
445
     *
446
     * @param superType The super class or interface type to extend.
447
     * @param <T>       A loaded type that the generated class is guaranteed to inherit.
448
     * @return A type builder for creating a new class extending the provided class or interface.
449
     */
450
    @SuppressWarnings("unchecked")
451
    public <T> DynamicType.Builder<T> subclass(Class<T> superType) {
452
        return (DynamicType.Builder<T>) subclass(TypeDescription.ForLoadedType.of(superType));
1✔
453
    }
454

455
    /**
456
     * <p>
457
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
458
     * this interface type is created.
459
     * </p>
460
     * <p>
461
     * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
462
     * </p>
463
     * <p>
464
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
465
     * types, a external cache or {@link TypeCache} should be used.
466
     * </p>
467
     *
468
     * @param superType           The super class or interface type to extend.
469
     * @param constructorStrategy A constructor strategy that determines the
470
     * @param <T>                 A loaded type that the generated class is guaranteed to inherit.
471
     * @return A type builder for creating a new class extending the provided class or interface.
472
     */
473
    @SuppressWarnings("unchecked")
474
    public <T> DynamicType.Builder<T> subclass(Class<T> superType, ConstructorStrategy constructorStrategy) {
475
        return (DynamicType.Builder<T>) subclass(TypeDescription.ForLoadedType.of(superType), constructorStrategy);
1✔
476
    }
477

478
    /**
479
     * <p>
480
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
481
     * this interface type is created.
482
     * </p>
483
     * <p>
484
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type. Any constructor is implemented
485
     * to only invoke its super type constructor of equal signature. Another behavior can be specified by supplying an explicit
486
     * {@link ConstructorStrategy} by {@link ByteBuddy#subclass(Type, ConstructorStrategy)}.
487
     * </p>
488
     * <p>
489
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
490
     * as raw types if they declare type variables.
491
     * </p>
492
     * <p>
493
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
494
     * types, a external cache or {@link TypeCache} should be used.
495
     * </p>
496
     *
497
     * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
498
     *                  variables that are referenced by the generic type must be declared by the generated subclass before creating
499
     *                  the type.
500
     * @return A type builder for creating a new class extending the provided class or interface.
501
     */
502
    public DynamicType.Builder<?> subclass(Type superType) {
UNCOV
503
        return subclass(TypeDefinition.Sort.describe(superType));
×
504
    }
505

506
    /**
507
     * <p>
508
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
509
     * this interface type is created.
510
     * </p>
511
     * <p>
512
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
513
     * as raw types if they declare type variables.
514
     * </p>
515
     * <p>
516
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
517
     * types, a external cache or {@link TypeCache} should be used.
518
     * </p>
519
     *
520
     * @param superType           The super class or interface type to extend. The type must be a raw type or parameterized
521
     *                            type. All type variables that are referenced by the generic type must be declared by the
522
     *                            generated subclass before creating the type.
523
     * @param constructorStrategy A constructor strategy that determines the
524
     * @return A type builder for creating a new class extending the provided class or interface.
525
     */
526
    public DynamicType.Builder<?> subclass(Type superType, ConstructorStrategy constructorStrategy) {
UNCOV
527
        return subclass(TypeDefinition.Sort.describe(superType), constructorStrategy);
×
528
    }
529

530
    /**
531
     * <p>
532
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
533
     * this interface type is created.
534
     * </p>
535
     * <p>
536
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type and sets them to be {@code public}.
537
     * Any constructor is implemented to only invoke its super type constructor of equal signature. Another behavior can be specified by
538
     * supplying an explicit {@link ConstructorStrategy} by {@link ByteBuddy#subclass(TypeDefinition, ConstructorStrategy)}.
539
     * </p>
540
     * <p>
541
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
542
     * as raw types if they declare type variables.
543
     * </p>
544
     * <p>
545
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
546
     * types, a external cache or {@link TypeCache} should be used.
547
     * </p>
548
     *
549
     * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
550
     *                  variables that are referenced by the generic type must be declared by the generated subclass before creating
551
     *                  the type.
552
     * @return A type builder for creating a new class extending the provided class or interface.
553
     */
554
    public DynamicType.Builder<?> subclass(TypeDefinition superType) {
555
        return subclass(superType, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING);
1✔
556
    }
557

558
    /**
559
     * <p>
560
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
561
     * this interface type is created.
562
     * </p>
563
     * <p>
564
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
565
     * as raw types if they declare type variables.
566
     * </p>
567
     * <p>
568
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
569
     * types, a external cache or {@link TypeCache} should be used.
570
     * </p>
571
     *
572
     * @param superType           The super class or interface type to extend. The type must be a raw type or parameterized
573
     *                            type. All type variables that are referenced by the generic type must be declared by the
574
     *                            generated subclass before creating the type.
575
     * @param constructorStrategy A constructor strategy that determines the
576
     * @return A type builder for creating a new class extending the provided class or interface.
577
     */
578
    public DynamicType.Builder<?> subclass(TypeDefinition superType, ConstructorStrategy constructorStrategy) {
579
        TypeDescription.Generic actualSuperType;
580
        TypeList.Generic interfaceTypes;
581
        if (superType.isPrimitive() || superType.isArray() || superType.isFinal()) {
1✔
582
            throw new IllegalArgumentException("Cannot subclass primitive, array or final types: " + superType);
1✔
583
        } else if (superType.isInterface()) {
1✔
584
            actualSuperType = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class);
1✔
585
            interfaceTypes = new TypeList.Generic.Explicit(superType);
1✔
586
        } else {
587
            actualSuperType = superType.asGenericType();
1✔
588
            interfaceTypes = new TypeList.Generic.Empty();
1✔
589
        }
590
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(namingStrategy.subclass(superType.asGenericType()),
1✔
591
                ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.PLAIN).resolve(superType.getModifiers()),
1✔
592
                actualSuperType).withInterfaces(interfaceTypes),
1✔
593
                classFileVersion,
594
                auxiliaryTypeNamingStrategy,
595
                annotationValueFilterFactory,
596
                annotationRetention,
597
                implementationContextFactory,
598
                methodGraphCompiler,
599
                typeValidation,
600
                visibilityBridgeStrategy,
601
                classReaderFactory,
602
                classWriterFactory,
603
                ignoredMethods,
604
                constructorStrategy);
605
    }
606

607
    /**
608
     * <p>
609
     * Creates a new, plain interface type.
610
     * </p>
611
     * <p>
612
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
613
     * types, a external cache or {@link TypeCache} should be used.
614
     * </p>
615
     *
616
     * @return A type builder that creates a new interface type.
617
     */
618
    public DynamicType.Builder<?> makeInterface() {
619
        return makeInterface(Collections.<TypeDescription>emptyList());
1✔
620
    }
621

622
    /**
623
     * <p>
624
     * Creates a new interface type that extends the provided interface.
625
     * </p>
626
     * <p>
627
     * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
628
     * </p>
629
     * <p>
630
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
631
     * types, a external cache or {@link TypeCache} should be used.
632
     * </p>
633
     *
634
     * @param interfaceType An interface type that the generated interface implements.
635
     * @param <T>           A loaded type that the generated interface is guaranteed to inherit.
636
     * @return A type builder that creates a new interface type.
637
     */
638
    @SuppressWarnings("unchecked")
639
    public <T> DynamicType.Builder<T> makeInterface(Class<T> interfaceType) {
640
        return (DynamicType.Builder<T>) makeInterface(Collections.<Type>singletonList(interfaceType));
1✔
641
    }
642

643
    /**
644
     * <p>
645
     * Creates a new interface type that extends the provided interface.
646
     * </p>
647
     * <p>
648
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
649
     * as raw types if they declare type variables or an owner type.
650
     * </p>
651
     * <p>
652
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
653
     * types, a external cache or {@link TypeCache} should be used.
654
     * </p>
655
     *
656
     * @param interfaceType The interface types to implement. The types must be raw or parameterized types. All type
657
     *                      variables that are referenced by a parameterized type must be declared by the generated
658
     *                      subclass before creating the type.
659
     * @return A type builder that creates a new interface type.
660
     */
661
    public DynamicType.Builder<?> makeInterface(Type... interfaceType) {
UNCOV
662
        return makeInterface(Arrays.asList(interfaceType));
×
663
    }
664

665
    /**
666
     * <p>
667
     * Creates a new interface type that extends the provided interface.
668
     * </p>
669
     * <p>
670
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
671
     * as raw types if they declare type variables or an owner type.
672
     * </p>
673
     * <p>
674
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
675
     * types, a external cache or {@link TypeCache} should be used.
676
     * </p>
677
     *
678
     * @param interfaceTypes The interface types to implement. The types must be raw or parameterized types. All
679
     *                       type variables that are referenced by a parameterized type must be declared by the
680
     *                       generated subclass before creating the type.
681
     * @return A type builder that creates a new interface type.
682
     */
683
    public DynamicType.Builder<?> makeInterface(List<? extends Type> interfaceTypes) {
684
        return makeInterface(new TypeList.Generic.ForLoadedTypes(interfaceTypes));
1✔
685
    }
686

687
    /**
688
     * <p>
689
     * Creates a new interface type that extends the provided interface.
690
     * </p>
691
     * <p>
692
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
693
     * as raw types if they declare type variables or an owner type.
694
     * </p>
695
     * <p>
696
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
697
     * types, a external cache or {@link TypeCache} should be used.
698
     * </p>
699
     *
700
     * @param interfaceType The interface types to implement. The types must be raw or parameterized types. All
701
     *                      type variables that are referenced by a parameterized type must be declared by the
702
     *                      generated subclass before creating the type.
703
     * @return A type builder that creates a new interface type.
704
     */
705
    public DynamicType.Builder<?> makeInterface(TypeDefinition... interfaceType) {
UNCOV
706
        return makeInterface(Arrays.asList(interfaceType));
×
707
    }
708

709
    /**
710
     * <p>
711
     * Creates a new interface type that extends the provided interface.
712
     * </p>
713
     * <p>
714
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
715
     * as raw types if they declare type variables or an owner type.
716
     * </p>
717
     * <p>
718
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
719
     * types, a external cache or {@link TypeCache} should be used.
720
     * </p>
721
     *
722
     * @param interfaceTypes The interface types to implement. The types must be raw or parameterized types. All
723
     *                       type variables that are referenced by a parameterized type must be declared by the
724
     *                       generated subclass before creating the type.
725
     * @return A type builder that creates a new interface type.
726
     */
727
    public DynamicType.Builder<?> makeInterface(Collection<? extends TypeDefinition> interfaceTypes) {
728
        return subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS).implement(interfaceTypes).modifiers(TypeManifestation.INTERFACE, Visibility.PUBLIC);
1✔
729
    }
730

731
    /**
732
     * <p>
733
     * Creates a new package definition. Package definitions are defined by classes named {@code package-info}
734
     * without any methods or fields but permit annotations. Any field or method definition will cause an
735
     * {@link IllegalStateException} to be thrown when the type is created.
736
     * </p>
737
     * <p>
738
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
739
     * types, a external cache or {@link TypeCache} should be used.
740
     * </p>
741
     *
742
     * @param name The fully qualified name of the package.
743
     * @return A type builder that creates a {@code package-info} class file.
744
     */
745
    public DynamicType.Builder<?> makePackage(String name) {
746
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(name + "." + PackageDescription.PACKAGE_CLASS_NAME,
1✔
747
                PackageDescription.PACKAGE_MODIFIERS,
748
                TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)),
1✔
749
                classFileVersion,
750
                auxiliaryTypeNamingStrategy,
751
                annotationValueFilterFactory,
752
                annotationRetention,
753
                implementationContextFactory,
754
                methodGraphCompiler,
755
                typeValidation,
756
                visibilityBridgeStrategy,
757
                classReaderFactory,
758
                classWriterFactory,
759
                ignoredMethods,
760
                ConstructorStrategy.Default.NO_CONSTRUCTORS);
761
    }
762

763
    /**
764
     * Creates a new Java record. This builder automatically defines fields for record members, standard accessors and a record constructor for any
765
     * defined record component.
766
     *
767
     * @return A dynamic type builder that creates a record.
768
     */
769
    public DynamicType.Builder<?> makeRecord() {
770
        TypeDescription.Generic record = InstrumentedType.Default.of(JavaType.RECORD.getTypeStub().getName(), TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class), Visibility.PUBLIC)
1✔
771
                .withMethod(new MethodDescription.Token(Opcodes.ACC_PROTECTED))
1✔
772
                .withMethod(new MethodDescription.Token("hashCode",
1✔
773
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
774
                        TypeDescription.ForLoadedType.of(int.class).asGenericType()))
1✔
775
                .withMethod(new MethodDescription.Token("equals",
1✔
776
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
777
                        TypeDescription.ForLoadedType.of(boolean.class).asGenericType(),
1✔
778
                        Collections.singletonList(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class))))
1✔
779
                .withMethod(new MethodDescription.Token("toString",
1✔
780
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
781
                        TypeDescription.ForLoadedType.of(String.class).asGenericType()))
1✔
782
                .asGenericType();
1✔
783
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(namingStrategy.subclass(record), Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, record).withRecord(true),
1✔
784
                classFileVersion,
785
                auxiliaryTypeNamingStrategy,
786
                annotationValueFilterFactory,
787
                annotationRetention,
788
                implementationContextFactory,
789
                methodGraphCompiler,
790
                typeValidation,
791
                visibilityBridgeStrategy,
792
                classReaderFactory,
793
                classWriterFactory,
794
                ignoredMethods,
795
                RecordConstructorStrategy.INSTANCE)
796
                .method(isHashCode()).intercept(RecordObjectMethod.HASH_CODE)
1✔
797
                .method(isEquals()).intercept(RecordObjectMethod.EQUALS)
1✔
798
                .method(isToString()).intercept(RecordObjectMethod.TO_STRING);
1✔
799
    }
800

801
    /**
802
     * Creates a new module with the given name.
803
     *
804
     * @param name                The name of the module.
805
     * @param modifierContributor The modifier contributors for the module.
806
     * @return A builder for a new module.
807
     */
808
    public DynamicType.Builder.ModuleDefinition<?> makeModule(String name,
809
                                                              ModifierContributor.ForModule... modifierContributor) {
UNCOV
810
        return makeModule(name, Arrays.asList(modifierContributor));
×
811
    }
812

813
    /**
814
     * Creates a new module with the given name.
815
     *
816
     * @param name                 The name of the module.
817
     * @param modifierContributors The modifier contributors for the module.
818
     * @return A builder for a new module.
819
     */
820
    public DynamicType.Builder.ModuleDefinition<?> makeModule(String name,
821
                                                              Collection<? extends ModifierContributor.ForModule> modifierContributors) {
UNCOV
822
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(ModuleDescription.MODULE_CLASS_NAME,
×
823
                Opcodes.ACC_MODULE,
824
                TypeDescription.Generic.UNDEFINED),
825
                classFileVersion,
826
                auxiliaryTypeNamingStrategy,
827
                annotationValueFilterFactory,
828
                annotationRetention,
829
                implementationContextFactory,
830
                methodGraphCompiler,
831
                typeValidation,
832
                visibilityBridgeStrategy,
833
                classReaderFactory,
834
                classWriterFactory,
835
                ignoredMethods,
UNCOV
836
                ConstructorStrategy.Default.NO_CONSTRUCTORS).module(name, modifierContributors);
×
837
    }
838

839
    /**
840
     * <p>
841
     * Creates a new {@link Annotation} type. Annotation properties are implemented as non-static, public methods with the
842
     * property type being defined as the return type.
843
     * </p>
844
     * <p>
845
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
846
     * types, a external cache or {@link TypeCache} should be used.
847
     * </p>
848
     *
849
     * @return A type builder that creates a new {@link Annotation} type.
850
     */
851
    public DynamicType.Builder<? extends Annotation> makeAnnotation() {
852
        return new SubclassDynamicTypeBuilder<Annotation>(instrumentedTypeFactory.subclass(namingStrategy.subclass(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Annotation.class)),
1✔
853
                ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.ANNOTATION).resolve(),
1✔
854
                TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)).withInterfaces(new TypeList.Generic.Explicit(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Annotation.class))),
1✔
855
                classFileVersion,
856
                auxiliaryTypeNamingStrategy,
857
                annotationValueFilterFactory,
858
                annotationRetention,
859
                implementationContextFactory,
860
                methodGraphCompiler,
861
                typeValidation,
862
                visibilityBridgeStrategy,
863
                classReaderFactory,
864
                classWriterFactory,
865
                ignoredMethods,
866
                ConstructorStrategy.Default.NO_CONSTRUCTORS);
867
    }
868

869
    /**
870
     * <p>
871
     * Creates a new {@link Enum} type.
872
     * </p>
873
     * <p>
874
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
875
     * types, a external cache or {@link TypeCache} should be used.
876
     * </p>
877
     *
878
     * @param value The names of the type's enumeration constants
879
     * @return A type builder for creating an enumeration type.
880
     */
881
    public DynamicType.Builder<? extends Enum<?>> makeEnumeration(String... value) {
882
        return makeEnumeration(Arrays.asList(value));
1✔
883
    }
884

885
    /**
886
     * <p>
887
     * Creates a new {@link Enum} type.
888
     * </p>
889
     * <p>
890
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
891
     * types, a external cache or {@link TypeCache} should be used.
892
     * </p>
893
     *
894
     * @param values The names of the type's enumeration constants
895
     * @return A type builder for creating an enumeration type.
896
     */
897
    public DynamicType.Builder<? extends Enum<?>> makeEnumeration(Collection<? extends String> values) {
898
        if (values.isEmpty()) {
1✔
899
            throw new IllegalArgumentException("Require at least one enumeration constant");
1✔
900
        }
901
        TypeDescription.Generic enumType = TypeDescription.Generic.Builder.parameterizedType(Enum.class, TargetType.class).build();
1✔
902
        return new SubclassDynamicTypeBuilder<Enum<?>>(instrumentedTypeFactory.subclass(namingStrategy.subclass(enumType),
1✔
903
                ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL, EnumerationState.ENUMERATION).resolve(),
1✔
904
                enumType),
905
                classFileVersion,
906
                auxiliaryTypeNamingStrategy,
907
                annotationValueFilterFactory,
908
                annotationRetention,
909
                implementationContextFactory,
910
                methodGraphCompiler,
911
                typeValidation,
912
                visibilityBridgeStrategy,
913
                classReaderFactory,
914
                classWriterFactory,
915
                ignoredMethods,
916
                ConstructorStrategy.Default.NO_CONSTRUCTORS)
917
                .defineConstructor(Visibility.PRIVATE).withParameters(String.class, int.class)
1✔
918
                .intercept(SuperMethodCall.INSTANCE)
1✔
919
                .defineMethod(EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME,
1✔
920
                        TargetType.class,
921
                        Visibility.PUBLIC, Ownership.STATIC).withParameters(String.class)
1✔
922
                .intercept(MethodCall.invoke(enumType.getDeclaredMethods()
1✔
923
                                .filter(named(EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME).and(takesArguments(Class.class, String.class))).getOnly())
1✔
924
                        .withOwnType().withArgument(0)
1✔
925
                        .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC))
1✔
926
                .defineMethod(EnumerationImplementation.ENUM_VALUES_METHOD_NAME,
1✔
927
                        TargetType[].class,
928
                        Visibility.PUBLIC, Ownership.STATIC)
929
                .intercept(new EnumerationImplementation(new ArrayList<String>(values)));
1✔
930
    }
931

932
    /**
933
     * <p>
934
     * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
935
     * by the new implementation.
936
     * </p>
937
     * <p>
938
     * The class file of the redefined type is located by querying the redefined type's class loader by name. For specifying an
939
     * alternative {@link ClassFileLocator}, use {@link ByteBuddy#redefine(Class, ClassFileLocator)}.
940
     * </p>
941
     * <p>
942
     * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
943
     * it is important that no fields or methods are added to the redefined class. Note that some {@link Implementation}s implicitly add fields or methods.
944
     * Finally, Byte Buddy might be forced to add a method if a redefined class already defines a class initializer. This can be disabled by setting
945
     * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
946
     * where the class initializer is retained <i>as is</i>.
947
     * </p>
948
     *
949
     * @param type The type that is being redefined.
950
     * @param <T>  The loaded type of the redefined type.
951
     * @return A type builder for redefining the provided type.
952
     */
953
    public <T> DynamicType.Builder<T> redefine(Class<T> type) {
954
        return redefine(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
955
    }
956

957
    /**
958
     * <p>
959
     * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
960
     * by the new implementation.
961
     * </p>
962
     * <p>
963
     * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
964
     * it is important that no fields or methods are added to the redefined class. Note that some {@link Implementation}s implicitly add fields or methods.
965
     * Finally, Byte Buddy might be forced to add a method if a redefined class already defines a class initializer. This can be disabled by setting
966
     * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
967
     * where the class initializer is retained <i>as is</i>.
968
     * </p>
969
     *
970
     * @param type             The type that is being redefined.
971
     * @param classFileLocator The class file locator that is queried for the redefined type's class file.
972
     * @param <T>              The loaded type of the redefined type.
973
     * @return A type builder for redefining the provided type.
974
     */
975
    public <T> DynamicType.Builder<T> redefine(Class<T> type, ClassFileLocator classFileLocator) {
976
        return redefine(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
977
    }
978

979
    /**
980
     * <p>
981
     * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
982
     * by the new implementation.
983
     * </p>
984
     * <p>
985
     * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
986
     * it is important that no fields or methods are added to the redefined class. Note that some {@link Implementation}s implicitly add fields or methods.
987
     * Finally, Byte Buddy might be forced to add a method if a redefined class already defines a class initializer. This can be disabled by setting
988
     * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
989
     * where the class initializer is retained <i>as is</i>.
990
     * </p>
991
     *
992
     * @param type             The type that is being redefined.
993
     * @param classFileLocator The class file locator that is queried for the redefined type's class file.
994
     * @param <T>              The loaded type of the redefined type.
995
     * @return A type builder for redefining the provided type.
996
     */
997
    public <T> DynamicType.Builder<T> redefine(TypeDescription type, ClassFileLocator classFileLocator) {
998
        if (type.isArray() || type.isPrimitive()) {
1✔
UNCOV
999
            throw new IllegalArgumentException("Cannot redefine array or primitive type: " + type);
×
1000
        }
1001
        return new RedefinitionDynamicTypeBuilder<T>(instrumentedTypeFactory.represent(type),
1✔
1002
                classFileVersion,
1003
                auxiliaryTypeNamingStrategy,
1004
                annotationValueFilterFactory,
1005
                annotationRetention,
1006
                implementationContextFactory,
1007
                methodGraphCompiler,
1008
                typeValidation,
1009
                visibilityBridgeStrategy,
1010
                classReaderFactory,
1011
                classWriterFactory,
1012
                ignoredMethods,
1013
                type,
1014
                classFileLocator);
1015
    }
1016

1017
    /**
1018
     * <p>
1019
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
1020
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
1021
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
1022
     * </p>
1023
     * <p>
1024
     * The class file of the rebased type is located by querying the rebased type's class loader by name. For specifying an
1025
     * alternative {@link ClassFileLocator}, use {@link ByteBuddy#redefine(Class, ClassFileLocator)}.
1026
     * </p>
1027
     *
1028
     * @param type The type that is being rebased.
1029
     * @param <T>  The loaded type of the rebased type.
1030
     * @return A type builder for rebasing the provided type.
1031
     */
1032
    public <T> DynamicType.Builder<T> rebase(Class<T> type) {
1033
        return rebase(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
1034
    }
1035

1036
    /**
1037
     * <p>
1038
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
1039
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
1040
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
1041
     * </p>
1042
     * <p>
1043
     * When a method is rebased, the original method is copied into a new method with a different name. These names are
1044
     * generated automatically by Byte Buddy unless a {@link MethodNameTransformer} is specified explicitly.
1045
     * Use {@link ByteBuddy#rebase(Class, ClassFileLocator, MethodNameTransformer)} for doing so.
1046
     * </p>
1047
     *
1048
     * @param type             The type that is being rebased.
1049
     * @param classFileLocator The class file locator that is queried for the rebased type's class file.
1050
     * @param <T>              The loaded type of the rebased type.
1051
     * @return A type builder for rebasing the provided type.
1052
     */
1053
    public <T> DynamicType.Builder<T> rebase(Class<T> type, ClassFileLocator classFileLocator) {
1054
        return rebase(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
1055
    }
1056

1057
    /**
1058
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
1059
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
1060
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
1061
     *
1062
     * @param type                  The type that is being rebased.
1063
     * @param classFileLocator      The class file locator that is queried for the rebased type's class file.
1064
     * @param methodNameTransformer The method name transformer for renaming a method that is rebased.
1065
     * @param <T>                   The loaded type of the rebased type.
1066
     * @return A type builder for rebasing the provided type.
1067
     */
1068
    public <T> DynamicType.Builder<T> rebase(Class<T> type, ClassFileLocator classFileLocator, MethodNameTransformer methodNameTransformer) {
UNCOV
1069
        return rebase(TypeDescription.ForLoadedType.of(type), classFileLocator, methodNameTransformer);
×
1070
    }
1071

1072
    /**
1073
     * <p>
1074
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
1075
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
1076
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
1077
     * </p>
1078
     * <p>
1079
     * When a method is rebased, the original method is copied into a new method with a different name. These names are
1080
     * generated automatically by Byte Buddy unless a {@link MethodNameTransformer} is specified explicitly.
1081
     * Use {@link ByteBuddy#rebase(TypeDescription, ClassFileLocator, MethodNameTransformer)} for doing so.
1082
     * </p>
1083
     *
1084
     * @param type             The type that is being rebased.
1085
     * @param classFileLocator The class file locator that is queried for the rebased type's class file.
1086
     * @param <T>              The loaded type of the rebased type.
1087
     * @return A type builder for rebasing the provided type.
1088
     */
1089
    public <T> DynamicType.Builder<T> rebase(TypeDescription type, ClassFileLocator classFileLocator) {
1090
        return rebase(type, classFileLocator, MethodNameTransformer.Suffixing.withRandomSuffix());
1✔
1091
    }
1092

1093
    /**
1094
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
1095
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
1096
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
1097
     *
1098
     * @param type                  The type that is being rebased.
1099
     * @param classFileLocator      The class file locator that is queried for the rebased type's class file.
1100
     * @param methodNameTransformer The method name transformer for renaming a method that is rebased.
1101
     * @param <T>                   The loaded type of the rebased type.
1102
     * @return A type builder for rebasing the provided type.
1103
     */
1104
    public <T> DynamicType.Builder<T> rebase(TypeDescription type, ClassFileLocator classFileLocator, MethodNameTransformer methodNameTransformer) {
1105
        if (type.isArray() || type.isPrimitive()) {
1✔
UNCOV
1106
            throw new IllegalArgumentException("Cannot rebase array or primitive type: " + type);
×
1107
        }
1108
        return new RebaseDynamicTypeBuilder<T>(instrumentedTypeFactory.represent(type),
1✔
1109
                classFileVersion,
1110
                auxiliaryTypeNamingStrategy,
1111
                annotationValueFilterFactory,
1112
                annotationRetention,
1113
                implementationContextFactory,
1114
                methodGraphCompiler,
1115
                typeValidation,
1116
                visibilityBridgeStrategy,
1117
                classReaderFactory,
1118
                classWriterFactory,
1119
                ignoredMethods,
1120
                type,
1121
                classFileLocator,
1122
                methodNameTransformer);
1123
    }
1124

1125
    /**
1126
     * Rebases a package. This offers an opportunity to add annotations to the package definition. Packages are defined
1127
     * by classes named {@code package-info} without any methods or fields but permit annotations. Any field or method
1128
     * definition will cause an {@link IllegalStateException} to be thrown when the type is created.
1129
     *
1130
     * @param aPackage         The package that is being rebased.
1131
     * @param classFileLocator The class file locator to use for locating the package's class file.
1132
     * @return A type builder for rebasing the given package.
1133
     */
1134
    public DynamicType.Builder<?> rebase(Package aPackage, ClassFileLocator classFileLocator) {
1135
        return rebase(new PackageDescription.ForLoadedPackage(aPackage), classFileLocator);
1✔
1136
    }
1137

1138
    /**
1139
     * Rebases a package. This offers an opportunity to add annotations to the package definition. Packages are defined
1140
     * by classes named {@code package-info} without any methods or fields but permit annotations. Any field or method
1141
     * definition will cause an {@link IllegalStateException} to be thrown when the type is created.
1142
     *
1143
     * @param aPackage         The package that is being rebased.
1144
     * @param classFileLocator The class file locator to use for locating the package's class file.
1145
     * @return A type builder for rebasing the given package.
1146
     */
1147
    public DynamicType.Builder<?> rebase(PackageDescription aPackage, ClassFileLocator classFileLocator) {
1148
        return rebase(new TypeDescription.ForPackageDescription(aPackage), classFileLocator);
1✔
1149
    }
1150

1151
    /**
1152
     * <p>
1153
     * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
1154
     * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
1155
     * when implementing a Java agent that only applies ASM-based code changes.
1156
     * </p>
1157
     * <p>
1158
     * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
1159
     * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
1160
     * {@link Implementation.Context.Factory} that does not attempt any type transformation.
1161
     * </p>
1162
     *
1163
     * @param type The type to decorate.
1164
     * @param <T>  The loaded type of the decorated type.
1165
     * @return A type builder for decorating the provided type.
1166
     */
1167
    public <T> DynamicType.Builder<T> decorate(Class<T> type) {
1168
        return decorate(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
1169
    }
1170

1171
    /**
1172
     * <p>
1173
     * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
1174
     * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
1175
     * when implementing a Java agent that only applies ASM-based code changes.
1176
     * </p>
1177
     * <p>
1178
     * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
1179
     * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
1180
     * {@link Implementation.Context.Factory} that does not attempt any type transformation.
1181
     * </p>
1182
     *
1183
     * @param type             The type to decorate.
1184
     * @param classFileLocator The class file locator to use.
1185
     * @param <T>              The loaded type of the decorated type.
1186
     * @return A type builder for decorating the provided type.
1187
     */
1188
    public <T> DynamicType.Builder<T> decorate(Class<T> type, ClassFileLocator classFileLocator) {
1189
        return decorate(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
1190
    }
1191

1192
    /**
1193
     * <p>
1194
     * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
1195
     * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
1196
     * when implementing a Java agent that only applies ASM-based code changes.
1197
     * </p>
1198
     * <p>
1199
     * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
1200
     * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
1201
     * {@link Implementation.Context.Factory} that does not attempt any type transformation.
1202
     * </p>
1203
     *
1204
     * @param type             The type to decorate.
1205
     * @param classFileLocator The class file locator to use.
1206
     * @param <T>              The loaded type of the decorated type.
1207
     * @return A type builder for decorating the provided type.
1208
     */
1209
    public <T> DynamicType.Builder<T> decorate(TypeDescription type, ClassFileLocator classFileLocator) {
1210
        if (type.isArray() || type.isPrimitive()) {
1✔
UNCOV
1211
            throw new IllegalArgumentException("Cannot decorate array or primitive type: " + type);
×
1212
        }
1213
        return new DecoratingDynamicTypeBuilder<T>(type,
1✔
1214
                classFileVersion,
1215
                auxiliaryTypeNamingStrategy,
1216
                annotationValueFilterFactory,
1217
                annotationRetention,
1218
                implementationContextFactory,
1219
                methodGraphCompiler,
1220
                typeValidation,
1221
                classReaderFactory,
1222
                classWriterFactory,
1223
                ignoredMethods,
1224
                classFileLocator);
1225
    }
1226

1227
    /**
1228
     * Creates a new configuration where all class files that are not based on an existing class file are created
1229
     * using the supplied class file version. When creating a Byte Buddy instance by {@link ByteBuddy#ByteBuddy()}, the class
1230
     * file version is detected automatically. If the class file version is known before creating a Byte Buddy instance, the
1231
     * {@link ByteBuddy#ByteBuddy(ClassFileVersion)} constructor should be used.
1232
     *
1233
     * @param classFileVersion The class file version to use for types that are not based on an existing class file.
1234
     * @return A new Byte Buddy instance that uses the supplied class file version.
1235
     */
1236
    public ByteBuddy with(ClassFileVersion classFileVersion) {
UNCOV
1237
        return new ByteBuddy(classFileVersion,
×
1238
                namingStrategy,
1239
                auxiliaryTypeNamingStrategy,
1240
                annotationValueFilterFactory,
1241
                annotationRetention,
1242
                implementationContextFactory,
1243
                methodGraphCompiler,
1244
                instrumentedTypeFactory,
1245
                typeValidation,
1246
                visibilityBridgeStrategy,
1247
                classReaderFactory,
1248
                classWriterFactory,
1249
                ignoredMethods);
1250
    }
1251

1252
    /**
1253
     * Creates a new configuration where new types are named by applying the given naming strategy. By default, Byte Buddy
1254
     * simply retains the name of rebased and redefined types but adds a random suffix to the name of created subclasses or
1255
     * -interfaces. If a type is defined within the {@code java.*} namespace, Byte Buddy also adds a suffix to the generated
1256
     * class because this namespace is only available for the bootstrap class loader.
1257
     *
1258
     * @param namingStrategy The naming strategy to apply when creating a new dynamic type.
1259
     * @return A new Byte Buddy instance that uses the supplied naming strategy.
1260
     */
1261
    public ByteBuddy with(NamingStrategy namingStrategy) {
1262
        return new ByteBuddy(classFileVersion,
1✔
1263
                namingStrategy,
1264
                auxiliaryTypeNamingStrategy,
1265
                annotationValueFilterFactory,
1266
                annotationRetention,
1267
                implementationContextFactory,
1268
                methodGraphCompiler,
1269
                instrumentedTypeFactory,
1270
                typeValidation,
1271
                visibilityBridgeStrategy,
1272
                classReaderFactory,
1273
                classWriterFactory,
1274
                ignoredMethods);
1275
    }
1276

1277
    /**
1278
     * Creates a new configuration where auxiliary types are named by applying the given naming strategy. Auxiliary types
1279
     * are helper types that might be required for implementing certain {@link Implementation}s. By default, Byte Buddy
1280
     * adds a random suffix to the instrumented type's name when naming its auxiliary types.
1281
     *
1282
     * @param auxiliaryTypeNamingStrategy The naming strategy to apply when creating a new auxiliary type.
1283
     * @return A new Byte Buddy instance that uses the supplied naming strategy for auxiliary types.
1284
     */
1285
    public ByteBuddy with(AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy) {
UNCOV
1286
        return new ByteBuddy(classFileVersion,
×
1287
                namingStrategy,
1288
                auxiliaryTypeNamingStrategy,
1289
                annotationValueFilterFactory,
1290
                annotationRetention,
1291
                implementationContextFactory,
1292
                methodGraphCompiler,
1293
                instrumentedTypeFactory,
1294
                typeValidation,
1295
                visibilityBridgeStrategy,
1296
                classReaderFactory,
1297
                classWriterFactory,
1298
                ignoredMethods);
1299
    }
1300

1301
    /**
1302
     * Creates a new configuration where annotation values are written according to the given filter factory. Using
1303
     * a filter factory, it is for example possible not to include certain values into a class file such that the
1304
     * runtime returns an annotation type's default value. By default, Byte Buddy includes all values into a class file,
1305
     * also such values for which a default value exists.
1306
     *
1307
     * @param annotationValueFilterFactory The annotation value filter factory to use.
1308
     * @return A new Byte Buddy instance that uses the supplied annotation value filter factory.
1309
     */
1310
    public ByteBuddy with(AnnotationValueFilter.Factory annotationValueFilterFactory) {
UNCOV
1311
        return new ByteBuddy(classFileVersion,
×
1312
                namingStrategy,
1313
                auxiliaryTypeNamingStrategy,
1314
                annotationValueFilterFactory,
1315
                annotationRetention,
1316
                implementationContextFactory,
1317
                methodGraphCompiler,
1318
                instrumentedTypeFactory,
1319
                typeValidation,
1320
                visibilityBridgeStrategy,
1321
                classReaderFactory,
1322
                classWriterFactory,
1323
                ignoredMethods);
1324
    }
1325

1326
    /**
1327
     * <p>
1328
     * Creates a new configuration where annotations that are found in an existing class file are or are not preserved
1329
     * in the format they are discovered, i.e. rewritten in the format they were already present in the class file.
1330
     * By default, Byte Buddy retains annotations when a class is rebased or redefined.
1331
     * </p>
1332
     * <p>
1333
     * <b>Warning</b>: Retaining annotations can cause problems when annotations of a field or method are added based
1334
     * on the annotations of a matched method. Doing so, Byte Buddy might write the annotations of the field or method
1335
     * explicitly to a class file while simultaneously retaining the existing annotation what results in duplicates.
1336
     * When matching fields or methods while adding annotations, disabling annotation retention might be required.
1337
     * </p>
1338
     *
1339
     * @param annotationRetention The annotation retention strategy to use.
1340
     * @return A new Byte Buddy instance that uses the supplied annotation retention strategy.
1341
     */
1342
    public ByteBuddy with(AnnotationRetention annotationRetention) {
1343
        return new ByteBuddy(classFileVersion,
1✔
1344
                namingStrategy,
1345
                auxiliaryTypeNamingStrategy,
1346
                annotationValueFilterFactory,
1347
                annotationRetention,
1348
                implementationContextFactory,
1349
                methodGraphCompiler,
1350
                instrumentedTypeFactory,
1351
                typeValidation,
1352
                visibilityBridgeStrategy,
1353
                classReaderFactory,
1354
                classWriterFactory,
1355
                ignoredMethods);
1356
    }
1357

1358
    /**
1359
     * Creates a new configuration where the {@link net.bytebuddy.implementation.Implementation.Context} of any created
1360
     * type is a product of the given implementation context factory. An implementation context might imply unwanted
1361
     * side-effects, for example, the creation of an additional synthetic methods in order to support specific features
1362
     * for realizing an {@link Implementation}. By default, Byte Buddy supplies a factory that enables all features. When
1363
     * redefining a loaded class, it is however required by the JVM that no additional members are added such that a
1364
     * {@link net.bytebuddy.implementation.Implementation.Context.Disabled} factory might be more appropriate.
1365
     *
1366
     * @param implementationContextFactory The implementation context factory to use for defining an instrumented type.
1367
     * @return A new Byte Buddy instance that uses the supplied implementation context factory.
1368
     */
1369
    public ByteBuddy with(Implementation.Context.Factory implementationContextFactory) {
1370
        return new ByteBuddy(classFileVersion,
1✔
1371
                namingStrategy,
1372
                auxiliaryTypeNamingStrategy,
1373
                annotationValueFilterFactory,
1374
                annotationRetention,
1375
                implementationContextFactory,
1376
                methodGraphCompiler,
1377
                instrumentedTypeFactory,
1378
                typeValidation,
1379
                visibilityBridgeStrategy,
1380
                classReaderFactory,
1381
                classWriterFactory,
1382
                ignoredMethods);
1383
    }
1384

1385
    /**
1386
     * Creates a new configuration where the {@link MethodGraph.Compiler} is used for creating a {@link MethodGraph}
1387
     * of the instrumented type. A method graph is a representation of a type's virtual methods, including all information
1388
     * on bridge methods that are inserted by the Java compiler. Creating a method graph is a rather expensive operation
1389
     * and more efficient strategies might exist for certain types or Java types that are created by alternative JVM
1390
     * languages. By default, a general purpose method graph compiler is used that uses the information that is exposed
1391
     * by the generic type information that is embedded in any class file.
1392
     *
1393
     * @param methodGraphCompiler The method graph compiler to use for analyzing the instrumented type.
1394
     * @return A new Byte Buddy instance that uses the supplied method graph compiler.
1395
     */
1396
    public ByteBuddy with(MethodGraph.Compiler methodGraphCompiler) {
1397
        return new ByteBuddy(classFileVersion,
1✔
1398
                namingStrategy,
1399
                auxiliaryTypeNamingStrategy,
1400
                annotationValueFilterFactory,
1401
                annotationRetention,
1402
                implementationContextFactory,
1403
                methodGraphCompiler,
1404
                instrumentedTypeFactory,
1405
                typeValidation,
1406
                visibilityBridgeStrategy,
1407
                classReaderFactory,
1408
                classWriterFactory,
1409
                ignoredMethods);
1410
    }
1411

1412
    /**
1413
     * Configures Byte Buddy to use the specified factory for creating {@link InstrumentedType}s. Doing so, more efficient
1414
     * representations can be chosen when only certain operations are required. By default, all operations are supported.
1415
     *
1416
     * @param instrumentedTypeFactory The factory to use when creating instrumented types.
1417
     * @return A new Byte Buddy instance that uses the supplied factory for creating instrumented types.
1418
     */
1419
    public ByteBuddy with(InstrumentedType.Factory instrumentedTypeFactory) {
1420
        return new ByteBuddy(classFileVersion,
1✔
1421
                namingStrategy,
1422
                auxiliaryTypeNamingStrategy,
1423
                annotationValueFilterFactory,
1424
                annotationRetention,
1425
                implementationContextFactory,
1426
                methodGraphCompiler,
1427
                instrumentedTypeFactory,
1428
                typeValidation,
1429
                visibilityBridgeStrategy,
1430
                classReaderFactory,
1431
                classWriterFactory,
1432
                ignoredMethods);
1433
    }
1434

1435
    /**
1436
     * Creates a new configuration that applies the supplied type validation. By default, explicitly type validation is applied
1437
     * by Byte Buddy but it might be disabled for performance reason or for voluntarily creating illegal types. The Java virtual
1438
     * machine applies its own type validation where some {@link Error} is thrown if a type is invalid, while Byte Buddy throws
1439
     * some {@link RuntimeException}.
1440
     *
1441
     * @param typeValidation The type validation to apply during type creation.
1442
     * @return A new Byte Buddy instance that applies the supplied type validation.
1443
     */
1444
    public ByteBuddy with(TypeValidation typeValidation) {
1445
        return new ByteBuddy(classFileVersion,
1✔
1446
                namingStrategy,
1447
                auxiliaryTypeNamingStrategy,
1448
                annotationValueFilterFactory,
1449
                annotationRetention,
1450
                implementationContextFactory,
1451
                methodGraphCompiler,
1452
                instrumentedTypeFactory,
1453
                typeValidation,
1454
                visibilityBridgeStrategy,
1455
                classReaderFactory,
1456
                classWriterFactory,
1457
                ignoredMethods);
1458
    }
1459

1460
    /**
1461
     * Creates a new configuration that applies the supplied visibility bridge strategy. By default, visibility bridges
1462
     * are create for all methods for which a visibility bridge is normally necessary.
1463
     *
1464
     * @param visibilityBridgeStrategy The visibility bridge strategy to apply.
1465
     * @return A new Byte Buddy instance that applies the supplied visibility bridge strategy.
1466
     */
1467
    public ByteBuddy with(VisibilityBridgeStrategy visibilityBridgeStrategy) {
1468
        return new ByteBuddy(classFileVersion,
1✔
1469
                namingStrategy,
1470
                auxiliaryTypeNamingStrategy,
1471
                annotationValueFilterFactory,
1472
                annotationRetention,
1473
                implementationContextFactory,
1474
                methodGraphCompiler,
1475
                instrumentedTypeFactory,
1476
                typeValidation,
1477
                visibilityBridgeStrategy,
1478
                classReaderFactory,
1479
                classWriterFactory,
1480
                ignoredMethods);
1481
    }
1482

1483
    /**
1484
     * Creates a new configuration that applies the supplied class writer strategy. By default, the constant pool of redefined and retransformed
1485
     * classes is retained as most changes are additive and this retention improves performance.
1486
     *
1487
     * @param classWriterStrategy The class writer strategy to apply during type creation.
1488
     * @return A new Byte Buddy instance that applies the supplied class writer strategy.
1489
     * @deprecated Use {@link ByteBuddy#with(AsmClassWriter.Factory)}.
1490
     */
1491
    @Deprecated
1492
    public ByteBuddy with(net.bytebuddy.dynamic.scaffold.ClassWriterStrategy classWriterStrategy) {
UNCOV
1493
        return new ByteBuddy(classFileVersion,
×
1494
                namingStrategy,
1495
                auxiliaryTypeNamingStrategy,
1496
                annotationValueFilterFactory,
1497
                annotationRetention,
1498
                implementationContextFactory,
1499
                methodGraphCompiler,
1500
                instrumentedTypeFactory,
1501
                typeValidation,
1502
                visibilityBridgeStrategy,
1503
                classReaderFactory,
1504
                new net.bytebuddy.dynamic.scaffold.ClassWriterStrategy.Delegating(classWriterStrategy),
1505
                ignoredMethods);
1506
    }
1507

1508
    /**
1509
     * Creates a new configuration that applies the supplied class reader factory.
1510
     *
1511
     * @param classReaderFactory The class reader factory to apply during type creation.
1512
     * @return A new Byte Buddy instance that applies the supplied class reader factory.
1513
     */
1514
    public ByteBuddy with(AsmClassReader.Factory classReaderFactory) {
UNCOV
1515
        return new ByteBuddy(classFileVersion,
×
1516
                namingStrategy,
1517
                auxiliaryTypeNamingStrategy,
1518
                annotationValueFilterFactory,
1519
                annotationRetention,
1520
                implementationContextFactory,
1521
                methodGraphCompiler,
1522
                instrumentedTypeFactory,
1523
                typeValidation,
1524
                visibilityBridgeStrategy,
1525
                classReaderFactory,
1526
                classWriterFactory,
1527
                ignoredMethods);
1528
    }
1529

1530
    /**
1531
     * Creates a new configuration that applies the supplied class writer factory.
1532
     *
1533
     * @param classWriterFactory The class writer factory to apply during type creation.
1534
     * @return A new Byte Buddy instance that applies the supplied class writer factory.
1535
     */
1536
    public ByteBuddy with(AsmClassWriter.Factory classWriterFactory) {
UNCOV
1537
        return new ByteBuddy(classFileVersion,
×
1538
                namingStrategy,
1539
                auxiliaryTypeNamingStrategy,
1540
                annotationValueFilterFactory,
1541
                annotationRetention,
1542
                implementationContextFactory,
1543
                methodGraphCompiler,
1544
                instrumentedTypeFactory,
1545
                typeValidation,
1546
                visibilityBridgeStrategy,
1547
                classReaderFactory,
1548
                classWriterFactory,
1549
                ignoredMethods);
1550
    }
1551

1552
    /**
1553
     * Creates a new configuration that ignores any original {@link AsmClassReader} while creating classes.
1554
     *
1555
     * @return A new Byte Buddy instance that applies the supplied class writer factory.
1556
     */
1557
    public ByteBuddy withIgnoredClassReader() {
UNCOV
1558
        if (classWriterFactory instanceof AsmClassWriter.Factory.Suppressing) {
×
UNCOV
1559
            return this;
×
1560
        }
UNCOV
1561
        return new ByteBuddy(classFileVersion,
×
1562
                namingStrategy,
1563
                auxiliaryTypeNamingStrategy,
1564
                annotationValueFilterFactory,
1565
                annotationRetention,
1566
                implementationContextFactory,
1567
                methodGraphCompiler,
1568
                instrumentedTypeFactory,
1569
                typeValidation,
1570
                visibilityBridgeStrategy,
1571
                classReaderFactory,
1572
                new AsmClassWriter.Factory.Suppressing(classWriterFactory),
1573
                ignoredMethods);
1574
    }
1575

1576
    /**
1577
     * Creates a new configuration where any {@link MethodDescription} that matches the provided method matcher is excluded
1578
     * from instrumentation. Any previous matcher for ignored methods is replaced. By default, Byte Buddy ignores any
1579
     * synthetic method (bridge methods are handled automatically) and the {@link Object#finalize()} method.
1580
     *
1581
     * @param ignoredMethods A matcher for identifying methods to be excluded from instrumentation.
1582
     * @return A new Byte Buddy instance that excludes any method from instrumentation if it is matched by the supplied matcher.
1583
     */
1584
    @SuppressWarnings("overloads")
1585
    public ByteBuddy ignore(ElementMatcher<? super MethodDescription> ignoredMethods) {
1586
        return ignore(new LatentMatcher.Resolved<MethodDescription>(ignoredMethods));
1✔
1587
    }
1588

1589
    /**
1590
     * <p>
1591
     * Creates a new configuration where any {@link MethodDescription} that matches the provided method matcher is excluded
1592
     * from instrumentation. Any previous matcher for ignored methods is replaced. By default, Byte Buddy ignores any
1593
     * synthetic method (bridge methods are handled automatically) and the {@link Object#finalize()} method. Using a latent
1594
     * matcher gives opportunity to resolve an {@link ElementMatcher} based on the instrumented type before applying the matcher.
1595
     * </p>
1596
     *
1597
     * @param ignoredMethods A matcher for identifying methods to be excluded from instrumentation.
1598
     * @return A new Byte Buddy instance that excludes any method from instrumentation if it is matched by the supplied matcher.
1599
     */
1600
    @SuppressWarnings("overloads")
1601
    public ByteBuddy ignore(LatentMatcher<? super MethodDescription> ignoredMethods) {
1602
        return new ByteBuddy(classFileVersion,
1✔
1603
                namingStrategy,
1604
                auxiliaryTypeNamingStrategy,
1605
                annotationValueFilterFactory,
1606
                annotationRetention,
1607
                implementationContextFactory,
1608
                methodGraphCompiler,
1609
                instrumentedTypeFactory,
1610
                typeValidation,
1611
                visibilityBridgeStrategy,
1612
                classReaderFactory,
1613
                classWriterFactory,
1614
                ignoredMethods);
1615
    }
1616

1617
    /**
1618
     * An implementation fo the {@code values} method of an enumeration type.
1619
     */
1620
    @HashCodeAndEqualsPlugin.Enhance
1621
    protected static class EnumerationImplementation implements Implementation {
1622

1623
        /**
1624
         * The name of the {@link java.lang.Object#clone()} method.
1625
         */
1626
        protected static final String CLONE_METHOD_NAME = "clone";
1627

1628
        /**
1629
         * The name of the {@code valueOf} method that is defined for any enumeration.
1630
         */
1631
        protected static final String ENUM_VALUE_OF_METHOD_NAME = "valueOf";
1632

1633
        /**
1634
         * The name of the {@code values} method that is defined for any enumeration.
1635
         */
1636
        protected static final String ENUM_VALUES_METHOD_NAME = "values";
1637

1638
        /**
1639
         * The field modifiers to use for any field that is added to an enumeration.
1640
         */
1641
        private static final int ENUM_FIELD_MODIFIERS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC;
1642

1643
        /**
1644
         * The name of the field containing an array of all enumeration values.
1645
         */
1646
        private static final String ENUM_VALUES = "$VALUES";
1647

1648
        /**
1649
         * The names of the enumerations to define for the enumeration.
1650
         */
1651
        private final List<String> values;
1652

1653
        /**
1654
         * Creates a new implementation of an enumeration type.
1655
         *
1656
         * @param values The values of the enumeration.
1657
         */
1658
        protected EnumerationImplementation(List<String> values) {
1✔
1659
            this.values = values;
1✔
1660
        }
1✔
1661

1662
        /**
1663
         * {@inheritDoc}
1664
         */
1665
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
1666
            for (String value : values) {
1✔
1667
                instrumentedType = instrumentedType.withField(new FieldDescription.Token(value,
1✔
1668
                        ENUM_FIELD_MODIFIERS | Opcodes.ACC_ENUM,
1669
                        TargetType.DESCRIPTION.asGenericType()));
1✔
1670
            }
1✔
1671
            return instrumentedType
1✔
1672
                    .withField(new FieldDescription.Token(ENUM_VALUES,
1✔
1673
                            ENUM_FIELD_MODIFIERS | Opcodes.ACC_SYNTHETIC,
1674
                            TypeDescription.ArrayProjection.of(TargetType.DESCRIPTION).asGenericType()))
1✔
1675
                    .withInitializer(new InitializationAppender(values));
1✔
1676
        }
1677

1678
        /**
1679
         * {@inheritDoc}
1680
         */
1681
        public ByteCodeAppender appender(Target implementationTarget) {
1682
            return new ValuesMethodAppender(implementationTarget.getInstrumentedType());
1✔
1683
        }
1684

1685
        /**
1686
         * A byte code appender for the {@code values} method of any enumeration type.
1687
         */
1688
        @HashCodeAndEqualsPlugin.Enhance
1689
        protected static class ValuesMethodAppender implements ByteCodeAppender {
1690

1691
            /**
1692
             * The instrumented enumeration type.
1693
             */
1694
            private final TypeDescription instrumentedType;
1695

1696
            /**
1697
             * Creates a new appender for the {@code values} method.
1698
             *
1699
             * @param instrumentedType The instrumented enumeration type.
1700
             */
1701
            protected ValuesMethodAppender(TypeDescription instrumentedType) {
1✔
1702
                this.instrumentedType = instrumentedType;
1✔
1703
            }
1✔
1704

1705
            /**
1706
             * {@inheritDoc}
1707
             */
1708
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1709
                FieldDescription valuesField = instrumentedType.getDeclaredFields().filter(named(ENUM_VALUES)).getOnly();
1✔
1710
                MethodDescription cloneMethod = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class).getDeclaredMethods().filter(named(CLONE_METHOD_NAME)).getOnly();
1✔
1711
                return new Size(new StackManipulation.Compound(
1✔
1712
                        FieldAccess.forField(valuesField).read(),
1✔
1713
                        MethodInvocation.invoke(cloneMethod).virtual(valuesField.getType().asErasure()),
1✔
1714
                        TypeCasting.to(valuesField.getType().asErasure()),
1✔
1715
                        MethodReturn.REFERENCE
1716
                ).apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
1717
            }
1718
        }
1719

1720
        /**
1721
         * A byte code appender for the type initializer of any enumeration type.
1722
         */
1723
        @HashCodeAndEqualsPlugin.Enhance
1724
        protected static class InitializationAppender implements ByteCodeAppender {
1725

1726
            /**
1727
             * The values of the enumeration that is being created.
1728
             */
1729
            private final List<String> values;
1730

1731
            /**
1732
             * Creates an appender for an enumerations type initializer.
1733
             *
1734
             * @param values The values of the enumeration that is being created.
1735
             */
1736
            protected InitializationAppender(List<String> values) {
1✔
1737
                this.values = values;
1✔
1738
            }
1✔
1739

1740
            /**
1741
             * {@inheritDoc}
1742
             */
1743
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1744
                TypeDescription instrumentedType = instrumentedMethod.getDeclaringType().asErasure();
1✔
1745
                MethodDescription enumConstructor = instrumentedType.getDeclaredMethods()
1✔
1746
                        .filter(isConstructor().and(takesArguments(String.class, int.class)))
1✔
1747
                        .getOnly();
1✔
1748
                int ordinal = 0;
1✔
1749
                StackManipulation stackManipulation = StackManipulation.Trivial.INSTANCE;
1✔
1750
                List<FieldDescription> enumerationFields = new ArrayList<FieldDescription>(values.size());
1✔
1751
                for (String value : values) {
1✔
1752
                    FieldDescription fieldDescription = instrumentedType.getDeclaredFields().filter(named(value)).getOnly();
1✔
1753
                    stackManipulation = new StackManipulation.Compound(stackManipulation,
1✔
1754
                            TypeCreation.of(instrumentedType),
1✔
1755
                            Duplication.SINGLE,
1756
                            new TextConstant(value),
1757
                            IntegerConstant.forValue(ordinal++),
1✔
1758
                            MethodInvocation.invoke(enumConstructor),
1✔
1759
                            FieldAccess.forField(fieldDescription).write());
1✔
1760
                    enumerationFields.add(fieldDescription);
1✔
1761
                }
1✔
1762
                List<StackManipulation> fieldGetters = new ArrayList<StackManipulation>(values.size());
1✔
1763
                for (FieldDescription fieldDescription : enumerationFields) {
1✔
1764
                    fieldGetters.add(FieldAccess.forField(fieldDescription).read());
1✔
1765
                }
1✔
1766
                stackManipulation = new StackManipulation.Compound(
1✔
1767
                        stackManipulation,
1768
                        ArrayFactory.forType(instrumentedType.asGenericType()).withValues(fieldGetters),
1✔
1769
                        FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(ENUM_VALUES)).getOnly()).write()
1✔
1770
                );
1771
                return new Size(stackManipulation.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
1772
            }
1773
        }
1774
    }
1775

1776
    /**
1777
     * A constructor strategy for implementing a Java record.
1778
     */
1779
    @HashCodeAndEqualsPlugin.Enhance
1✔
1780
    protected enum RecordConstructorStrategy implements ConstructorStrategy, Implementation {
1781

1782
        /**
1783
         * The singleton instance.
1784
         */
1785
        INSTANCE;
1✔
1786

1787
        /**
1788
         * {@inheritDoc}
1789
         */
1790
        public List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType) {
1791
            List<ParameterDescription.Token> tokens = new ArrayList<ParameterDescription.Token>(instrumentedType.getRecordComponents().size());
1✔
1792
            for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1✔
1793
                tokens.add(new ParameterDescription.Token(recordComponent.getType(),
×
UNCOV
1794
                        recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.CONSTRUCTOR)),
×
1795
                        recordComponent.getActualName(),
×
1796
                        ModifierContributor.EMPTY_MASK));
×
1797
            }
×
1798
            return Collections.singletonList(new MethodDescription.Token(MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
1✔
1799
                    Opcodes.ACC_PUBLIC,
1800
                    Collections.<TypeVariableToken>emptyList(),
1✔
1801
                    TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(void.class),
1✔
1802
                    tokens,
1803
                    Collections.<TypeDescription.Generic>emptyList(),
1✔
1804
                    Collections.<AnnotationDescription>emptyList(),
1✔
1805
                    AnnotationValue.UNDEFINED,
1806
                    TypeDescription.Generic.UNDEFINED));
1807
        }
1808

1809
        /**
1810
         * {@inheritDoc}
1811
         */
1812
        public MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry) {
1813
            return methodRegistry.prepend(new LatentMatcher.Resolved<MethodDescription>(isConstructor().and(takesGenericArguments(instrumentedType.getRecordComponents().asTypeList()))),
1✔
1814
                    new MethodRegistry.Handler.ForImplementation(this),
1815
                    MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER,
1816
                    Transformer.ForMethod.NoOp.<MethodDescription>make());
1✔
1817
        }
1818

1819
        /**
1820
         * {@inheritDoc}
1821
         */
1822
        public ByteCodeAppender appender(Target implementationTarget) {
1823
            return new Appender(implementationTarget.getInstrumentedType());
1✔
1824
        }
1825

1826
        /**
1827
         * {@inheritDoc}
1828
         */
1829
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
1830
            for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1✔
UNCOV
1831
                instrumentedType = instrumentedType
×
UNCOV
1832
                        .withField(new FieldDescription.Token(recordComponent.getActualName(),
×
1833
                                Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL,
1834
                                recordComponent.getType(),
×
1835
                                recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.FIELD))))
×
1836
                        .withMethod(new MethodDescription.Token(recordComponent.getActualName(),
×
1837
                                Opcodes.ACC_PUBLIC,
1838
                                Collections.<TypeVariableToken>emptyList(),
×
1839
                                recordComponent.getType(),
×
UNCOV
1840
                                Collections.<ParameterDescription.Token>emptyList(),
×
1841
                                Collections.<TypeDescription.Generic>emptyList(),
×
1842
                                recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.METHOD)),
×
1843
                                AnnotationValue.UNDEFINED,
1844
                                TypeDescription.Generic.UNDEFINED));
1845
            }
×
1846
            return instrumentedType;
1✔
1847
        }
1848

1849
        /**
1850
         * A byte code appender for accessors and the record constructor.
1851
         */
1852
        @HashCodeAndEqualsPlugin.Enhance
1853
        protected static class Appender implements ByteCodeAppender {
1854

1855
            /**
1856
             * The instrumented type.
1857
             */
1858
            private final TypeDescription instrumentedType;
1859

1860
            /**
1861
             * Creates a new byte code appender for accessors and the record constructor.
1862
             *
1863
             * @param instrumentedType The instrumented type.
1864
             */
1865
            protected Appender(TypeDescription instrumentedType) {
1✔
1866
                this.instrumentedType = instrumentedType;
1✔
1867
            }
1✔
1868

1869
            /**
1870
             * {@inheritDoc}
1871
             */
1872
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
UNCOV
1873
                if (instrumentedMethod.isMethod()) {
×
UNCOV
1874
                    return new Simple(
×
UNCOV
1875
                            MethodVariableAccess.loadThis(),
×
UNCOV
1876
                            FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(instrumentedMethod.getName())).getOnly()).read(),
×
UNCOV
1877
                            MethodReturn.of(instrumentedMethod.getReturnType())
×
UNCOV
1878
                    ).apply(methodVisitor, implementationContext, instrumentedMethod);
×
1879
                } else {
UNCOV
1880
                    List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(instrumentedType.getRecordComponents().size() * 3 + 2);
×
UNCOV
1881
                    stackManipulations.add(MethodVariableAccess.loadThis());
×
UNCOV
1882
                    stackManipulations.add(MethodInvocation.invoke(new MethodDescription.Latent(JavaType.RECORD.getTypeStub(), new MethodDescription.Token(Opcodes.ACC_PUBLIC))));
×
UNCOV
1883
                    int offset = 1;
×
UNCOV
1884
                    for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
×
UNCOV
1885
                        stackManipulations.add(MethodVariableAccess.loadThis());
×
UNCOV
1886
                        stackManipulations.add(MethodVariableAccess.of(recordComponent.getType()).loadFrom(offset));
×
UNCOV
1887
                        stackManipulations.add(FieldAccess.forField(instrumentedType.getDeclaredFields()
×
UNCOV
1888
                                .filter(named(recordComponent.getActualName()))
×
UNCOV
1889
                                .getOnly()).write());
×
UNCOV
1890
                        offset += recordComponent.getType().getStackSize().getSize();
×
UNCOV
1891
                    }
×
UNCOV
1892
                    stackManipulations.add(MethodReturn.VOID);
×
UNCOV
1893
                    return new Simple(stackManipulations).apply(methodVisitor, implementationContext, instrumentedMethod);
×
1894
                }
1895
            }
1896
        }
1897
    }
1898

1899
    /**
1900
     * Implements the object methods of the Java record type.
1901
     */
1902
    @HashCodeAndEqualsPlugin.Enhance
1✔
1903
    protected enum RecordObjectMethod implements Implementation {
1904

1905
        /**
1906
         * The {@code hashCode} method.
1907
         */
1908
        HASH_CODE("hashCode", StackManipulation.Trivial.INSTANCE, int.class),
1✔
1909

1910
        /**
1911
         * The {@code equals} method.
1912
         */
1913
        EQUALS("equals", MethodVariableAccess.REFERENCE.loadFrom(1), boolean.class, Object.class),
1✔
1914

1915
        /**
1916
         * The {@code toString} method.
1917
         */
1918
        TO_STRING("toString", StackManipulation.Trivial.INSTANCE, String.class);
1✔
1919

1920
        /**
1921
         * The method name.
1922
         */
1923
        private final String name;
1924

1925
        /**
1926
         * The stack manipulation to append to the arguments.
1927
         */
1928
        private final StackManipulation stackManipulation;
1929

1930
        /**
1931
         * The return type.
1932
         */
1933
        private final TypeDescription returnType;
1934

1935
        /**
1936
         * The arguments type.
1937
         */
1938
        private final List<? extends TypeDescription> arguments;
1939

1940
        /**
1941
         * Creates a new object method instance for a Java record.
1942
         *
1943
         * @param name              The method name.
1944
         * @param stackManipulation The stack manipulation to append to the arguments.
1945
         * @param returnType        The return type.
1946
         * @param arguments         The arguments type.
1947
         */
1948
        RecordObjectMethod(String name, StackManipulation stackManipulation, Class<?> returnType, Class<?>... arguments) {
1✔
1949
            this.name = name;
1✔
1950
            this.stackManipulation = stackManipulation;
1✔
1951
            this.returnType = TypeDescription.ForLoadedType.of(returnType);
1✔
1952
            this.arguments = new TypeList.ForLoadedTypes(arguments);
1✔
1953
        }
1✔
1954

1955
        /**
1956
         * {@inheritDoc}
1957
         */
1958
        public ByteCodeAppender appender(Target implementationTarget) {
1959
            StringBuilder stringBuilder = new StringBuilder();
1✔
1960
            List<JavaConstant> methodHandles = new ArrayList<JavaConstant>(implementationTarget.getInstrumentedType().getRecordComponents().size());
1✔
1961
            for (RecordComponentDescription.InDefinedShape recordComponent : implementationTarget.getInstrumentedType().getRecordComponents()) {
1✔
UNCOV
1962
                if (stringBuilder.length() > 0) {
×
UNCOV
1963
                    stringBuilder.append(";");
×
1964
                }
UNCOV
1965
                stringBuilder.append(recordComponent.getActualName());
×
UNCOV
1966
                methodHandles.add(JavaConstant.MethodHandle.ofGetter(implementationTarget.getInstrumentedType().getDeclaredFields()
×
UNCOV
1967
                        .filter(named(recordComponent.getActualName()))
×
UNCOV
1968
                        .getOnly()));
×
UNCOV
1969
            }
×
1970
            return new ByteCodeAppender.Simple(MethodVariableAccess.loadThis(),
1✔
1971
                    stackManipulation,
1972
                    MethodInvocation.invoke(new MethodDescription.Latent(JavaType.OBJECT_METHODS.getTypeStub(), new MethodDescription.Token("bootstrap",
1✔
1973
                            Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
1974
                            TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class),
1✔
1975
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub().asGenericType(),
1✔
1976
                                    TypeDescription.ForLoadedType.of(String.class).asGenericType(),
1✔
1977
                                    JavaType.TYPE_DESCRIPTOR.getTypeStub().asGenericType(),
1✔
1978
                                    TypeDescription.ForLoadedType.of(Class.class).asGenericType(),
1✔
1979
                                    TypeDescription.ForLoadedType.of(String.class).asGenericType(),
1✔
1980
                                    TypeDescription.ArrayProjection.of(JavaType.METHOD_HANDLE.getTypeStub()).asGenericType())))).dynamic(name,
1✔
1981
                            returnType,
1982
                            CompoundList.of(implementationTarget.getInstrumentedType(), arguments),
1✔
1983
                            CompoundList.of(Arrays.asList(JavaConstant.Simple.of(implementationTarget.getInstrumentedType()), JavaConstant.Simple.ofLoaded(stringBuilder.toString())), methodHandles)),
1✔
1984
                    MethodReturn.of(returnType));
1✔
1985
        }
1986

1987
        /**
1988
         * {@inheritDoc}
1989
         */
1990
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
1991
            return instrumentedType;
1✔
1992
        }
1993
    }
1994
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc