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

raphw / byte-buddy / #641

19 Aug 2024 10:38PM CUT coverage: 85.389% (-0.06%) from 85.448%
#641

push

raphw
Disable validation for minor breakage of protected API.

28759 of 33680 relevant lines covered (85.39%)

0.85 hits per line

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

71.38
/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.*;
26
import net.bytebuddy.description.type.*;
27
import net.bytebuddy.dynamic.*;
28
import net.bytebuddy.dynamic.scaffold.*;
29
import net.bytebuddy.dynamic.scaffold.inline.DecoratingDynamicTypeBuilder;
30
import net.bytebuddy.dynamic.scaffold.inline.MethodNameTransformer;
31
import net.bytebuddy.dynamic.scaffold.inline.RebaseDynamicTypeBuilder;
32
import net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder;
33
import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
34
import net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder;
35
import net.bytebuddy.implementation.Implementation;
36
import net.bytebuddy.implementation.MethodCall;
37
import net.bytebuddy.implementation.SuperMethodCall;
38
import net.bytebuddy.implementation.attribute.AnnotationRetention;
39
import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
40
import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
41
import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
42
import net.bytebuddy.implementation.bytecode.*;
43
import net.bytebuddy.implementation.bytecode.assign.Assigner;
44
import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
45
import net.bytebuddy.implementation.bytecode.collection.ArrayFactory;
46
import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
47
import net.bytebuddy.implementation.bytecode.constant.TextConstant;
48
import net.bytebuddy.implementation.bytecode.member.FieldAccess;
49
import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
50
import net.bytebuddy.implementation.bytecode.member.MethodReturn;
51
import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
52
import net.bytebuddy.matcher.ElementMatcher;
53
import net.bytebuddy.matcher.LatentMatcher;
54
import net.bytebuddy.utility.*;
55
import net.bytebuddy.utility.nullability.MaybeNull;
56
import net.bytebuddy.utility.privilege.GetSystemPropertyAction;
57
import org.objectweb.asm.MethodVisitor;
58
import org.objectweb.asm.Opcodes;
59

60
import java.lang.annotation.Annotation;
61
import java.lang.annotation.ElementType;
62
import java.lang.reflect.Type;
63
import java.security.PrivilegedAction;
64
import java.util.*;
65

66
import static net.bytebuddy.matcher.ElementMatchers.*;
67

68
/**
69
 * Instances of this class serve as a focus point for configuration of the library's behavior and as an entry point
70
 * to any form of code generation using the library. For this purpose, Byte Buddy offers a fluent API which allows
71
 * for the step-wise generation of a new Java type. A type is generated either by:
72
 * <ul>
73
 * <li><b>Subclassing</b> some type: A subclass - as the name suggests - extends another, existing Java type. Virtual
74
 * members of the generated type's super types can be overridden. Subclasses can also be interface extensions of one
75
 * or several interfaces.</li>
76
 * <li><b>Redefining</b> a type: By redefining a type, it is not only possible to override virtual methods of the
77
 * redefined type but also to redefine existing methods. This way, it is also possible to change the behavior of
78
 * non-virtual methods and constructors of the redefined type.</li>
79
 * <li><b>Rebasing</b> a type: Rebasing a type works similar to creating a subclass, i.e. any method being overridden
80
 * is still capable of invoking any original code of the rebased type. Any rebased method is however inlined into the
81
 * rebased type and any original code is preserved automatically. This way, the type's identity does not change.</li>
82
 * </ul>
83
 * Byte Buddy's API does not change when a type is rebased, redefined or subclassed. All types are created via the
84
 * {@link net.bytebuddy.dynamic.DynamicType.Builder} interface. Byte Buddy's API is expressed by fully immutable
85
 * components and is therefore thread-safe. As a consequence, method calls must be chained for all of Byte Buddy's
86
 * component, e.g. a method call like the following has no effect:
87
 * <pre>
88
 * ByteBuddy byteBuddy = new ByteBuddy();
89
 * byteBuddy.foo()</pre>
90
 * Instead, the following method chain is correct use of the API:
91
 * <pre>
92
 * ByteBuddy byteBuddy = new ByteBuddy().foo();</pre>
93
 * <p>
94
 * For the creation of Java agents, Byte Buddy offers a convenience API implemented by the
95
 * {@link net.bytebuddy.agent.builder.AgentBuilder}. The API wraps a {@link ByteBuddy} instance and offers agent-specific
96
 * configuration opportunities by integrating against the {@link java.lang.instrument.Instrumentation} API.
97
 * </p>
98
 *
99
 * @see net.bytebuddy.agent.builder.AgentBuilder
100
 */
101
@HashCodeAndEqualsPlugin.Enhance
102
public class ByteBuddy {
103

104
    /**
105
     * A property that controls the default naming strategy. If not set, Byte Buddy is generating
106
     * random names for types that are not named explicitly. If set to {@code fixed}, Byte Buddy is
107
     * setting names deterministically without any random element, or to {@code caller}, if a name
108
     * should be fixed but contain the name of the caller class and method. If set to a numeric
109
     * value, Byte Buddy is generating random names, using the number as a seed.
110
     */
111
    public static final String DEFAULT_NAMING_PROPERTY = "net.bytebuddy.naming";
112

113
    /**
114
     * A property that controls the default type validation applied by Byte Buddy. If not set,
115
     * and if not otherwise configured by the user, types will be explicitly validated to
116
     * supply better error messages.
117
     */
118
    public static final String DEFAULT_VALIDATION_PROPERTY = "net.bytebuddy.validation";
119

120
    /**
121
     * The default prefix for the default {@link net.bytebuddy.NamingStrategy}.
122
     */
123
    private static final String BYTE_BUDDY_DEFAULT_PREFIX = "ByteBuddy";
124

125
    /**
126
     * The default suffix when defining a {@link AuxiliaryType.NamingStrategy}.
127
     */
128
    private static final String BYTE_BUDDY_DEFAULT_SUFFIX = "auxiliary";
129

130
    /**
131
     * The default name of a fixed context name for synthetic fields and methods.
132
     */
133
    private static final String BYTE_BUDDY_DEFAULT_CONTEXT_NAME = "synthetic";
134

135
    /**
136
     * The default type validation to apply.
137
     */
138
    private static final TypeValidation DEFAULT_TYPE_VALIDATION;
139

140
    /**
141
     * The default naming strategy or {@code null} if no such strategy is set.
142
     */
143
    @MaybeNull
144
    private static final NamingStrategy DEFAULT_NAMING_STRATEGY;
145

146
    /**
147
     * The default auxiliary naming strategy or {@code null} if no such strategy is set.
148
     */
149
    @MaybeNull
150
    private static final AuxiliaryType.NamingStrategy DEFAULT_AUXILIARY_NAMING_STRATEGY;
151

152
    /**
153
     * The default implementation context factory or {@code null} if no such factory is set.
154
     */
155
    @MaybeNull
156
    private static final Implementation.Context.Factory DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY;
157

158
    /*
159
     * Resolves the default naming strategy.
160
     */
161
    static {
162
        String validation;
163
        try {
164
            validation = doPrivileged(new GetSystemPropertyAction(DEFAULT_VALIDATION_PROPERTY));
1✔
165
        } catch (Throwable ignored) {
×
166
            validation = null;
×
167
        }
1✔
168
        DEFAULT_TYPE_VALIDATION = validation == null || Boolean.parseBoolean(validation)
1✔
169
                ? TypeValidation.ENABLED
170
                : TypeValidation.DISABLED;
171
        String naming;
172
        try {
173
            naming = doPrivileged(new GetSystemPropertyAction(DEFAULT_NAMING_PROPERTY));
1✔
174
        } catch (Throwable ignored) {
×
175
            naming = null;
×
176
        }
1✔
177
        NamingStrategy namingStrategy;
178
        AuxiliaryType.NamingStrategy auxiliaryNamingStrategy;
179
        Implementation.Context.Factory implementationContextFactory;
180
        if (naming == null) {
1✔
181
            if (GraalImageCode.getCurrent().isDefined()) {
1✔
182
                namingStrategy = new NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_PREFIX,
×
183
                        new NamingStrategy.Suffixing.BaseNameResolver.WithCallerSuffix(NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE),
184
                        NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE);
185
                auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
186
                implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
187
            } else {
188
                namingStrategy = null;
1✔
189
                auxiliaryNamingStrategy = null;
1✔
190
                implementationContextFactory = null;
1✔
191
            }
192
        } else if (naming.equalsIgnoreCase("fixed")) {
×
193
            namingStrategy = new NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_PREFIX,
×
194
                    NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE,
195
                    NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE);
196
            auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
197
            implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
198
        } else if (naming.equalsIgnoreCase("caller")) {
×
199
            namingStrategy = new NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_PREFIX,
×
200
                    new NamingStrategy.Suffixing.BaseNameResolver.WithCallerSuffix(NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE),
201
                    NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE);
202
            auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
203
            implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
204
        } else {
205
            long seed;
206
            try {
207
                seed = Long.parseLong(naming);
×
208
            } catch (Exception ignored) {
×
209
                throw new IllegalStateException("'net.bytebuddy.naming' is set to an unknown, non-numeric value: " + naming);
×
210
            }
×
211
            namingStrategy = new NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_PREFIX,
×
212
                    NamingStrategy.Suffixing.BaseNameResolver.ForUnnamedType.INSTANCE,
213
                    NamingStrategy.BYTE_BUDDY_RENAME_PACKAGE,
214
                    new RandomString(RandomString.DEFAULT_LENGTH, new Random(seed)));
215
            auxiliaryNamingStrategy = new AuxiliaryType.NamingStrategy.Suffixing(BYTE_BUDDY_DEFAULT_SUFFIX);
×
216
            implementationContextFactory = new Implementation.Context.Default.Factory.WithFixedSuffix(BYTE_BUDDY_DEFAULT_CONTEXT_NAME);
×
217
        }
218
        DEFAULT_NAMING_STRATEGY = namingStrategy;
1✔
219
        DEFAULT_AUXILIARY_NAMING_STRATEGY = auxiliaryNamingStrategy;
1✔
220
        DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY = implementationContextFactory;
1✔
221
    }
1✔
222

223
    /**
224
     * A proxy for {@code java.security.AccessController#doPrivileged} that is activated if available.
225
     *
226
     * @param action The action to execute from a privileged context.
227
     * @param <T>    The type of the action's resolved value.
228
     * @return The action's resolved value.
229
     */
230
    @MaybeNull
231
    @AccessControllerPlugin.Enhance
232
    private static <T> T doPrivileged(PrivilegedAction<T> action) {
233
        return action.run();
×
234
    }
235

236
    /**
237
     * The class file version to use for types that are not based on an existing class file.
238
     */
239
    protected final ClassFileVersion classFileVersion;
240

241
    /**
242
     * The naming strategy to use.
243
     */
244
    protected final NamingStrategy namingStrategy;
245

246
    /**
247
     * The naming strategy to use for naming auxiliary types.
248
     */
249
    protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
250

251
    /**
252
     * The annotation value filter factory to use.
253
     */
254
    protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
255

256
    /**
257
     * The annotation retention strategy to use.
258
     */
259
    protected final AnnotationRetention annotationRetention;
260

261
    /**
262
     * The implementation context factory to use.
263
     */
264
    protected final Implementation.Context.Factory implementationContextFactory;
265

266
    /**
267
     * The method graph compiler to use.
268
     */
269
    protected final MethodGraph.Compiler methodGraphCompiler;
270

271
    /**
272
     * The instrumented type factory to use.
273
     */
274
    protected final InstrumentedType.Factory instrumentedTypeFactory;
275

276
    /**
277
     * A matcher for identifying methods that should be excluded from instrumentation.
278
     */
279
    protected final LatentMatcher<? super MethodDescription> ignoredMethods;
280

281
    /**
282
     * Determines if a type should be explicitly validated.
283
     */
284
    protected final TypeValidation typeValidation;
285

286
    /**
287
     * The visibility bridge strategy to apply.
288
     */
289
    protected final VisibilityBridgeStrategy visibilityBridgeStrategy;
290

291
    /**
292
     * The class reader factory to use.
293
     */
294
    protected final AsmClassReader.Factory classReaderFactory;
295

296
    /**
297
     * The class writer factory to use.
298
     */
299
    protected final AsmClassWriter.Factory classWriterFactory;
300

301
    /**
302
     * <p>
303
     * Creates a new Byte Buddy instance with a default configuration that is suitable for most use cases.
304
     * </p>
305
     * <p>
306
     * When creating this configuration, Byte Buddy attempts to discover the current JVM's version. If this
307
     * is not possible, class files are created Java 6-compatible.
308
     * </p>
309
     *
310
     * @see ClassFileVersion#ofThisVm(ClassFileVersion)
311
     */
312
    public ByteBuddy() {
313
        this(ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V5));
1✔
314
    }
1✔
315

316
    /**
317
     * Creates a new Byte Buddy instance with a default configuration that is suitable for most use cases.
318
     *
319
     * @param classFileVersion The class file version to use for types that are not based on an existing class file.
320
     */
321
    public ByteBuddy(ClassFileVersion classFileVersion) {
322
        this(classFileVersion,
1✔
323
                DEFAULT_NAMING_STRATEGY == null
324
                        ? new NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_PREFIX)
325
                        : DEFAULT_NAMING_STRATEGY,
326
                DEFAULT_AUXILIARY_NAMING_STRATEGY == null
327
                        ? new AuxiliaryType.NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_SUFFIX)
328
                        : DEFAULT_AUXILIARY_NAMING_STRATEGY,
329
                AnnotationValueFilter.Default.APPEND_DEFAULTS,
330
                AnnotationRetention.ENABLED,
331
                DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY == null
332
                        ? Implementation.Context.Default.Factory.INSTANCE
333
                        : DEFAULT_IMPLEMENTATION_CONTEXT_FACTORY,
334
                MethodGraph.Compiler.DEFAULT,
335
                InstrumentedType.Factory.Default.MODIFIABLE,
336
                DEFAULT_TYPE_VALIDATION,
337
                VisibilityBridgeStrategy.Default.ALWAYS,
338
                AsmClassReader.Factory.Default.INSTANCE,
339
                AsmClassWriter.Factory.Default.INSTANCE,
340
                new LatentMatcher.Resolved<MethodDescription>(isSynthetic().or(isDefaultFinalizer())));
1✔
341
    }
1✔
342

343
    /**
344
     * Creates a new Byte Buddy instance.
345
     *
346
     * @param classFileVersion             The class file version to use for types that are not based on an existing class file.
347
     * @param namingStrategy               The naming strategy to use.
348
     * @param auxiliaryTypeNamingStrategy  The naming strategy to use for naming auxiliary types.
349
     * @param annotationValueFilterFactory The annotation value filter factory to use.
350
     * @param annotationRetention          The annotation retention strategy to use.
351
     * @param implementationContextFactory The implementation context factory to use.
352
     * @param methodGraphCompiler          The method graph compiler to use.
353
     * @param instrumentedTypeFactory      The instrumented type factory to use.
354
     * @param typeValidation               Determines if a type should be explicitly validated.
355
     * @param visibilityBridgeStrategy     The visibility bridge strategy to apply.
356
     * @param classReaderFactory           The class reader factory to use.
357
     * @param classWriterFactory           The class writer factory to use.
358
     * @param ignoredMethods               A matcher for identifying methods that should be excluded from instrumentation.
359
     */
360
    protected ByteBuddy(ClassFileVersion classFileVersion,
361
                        NamingStrategy namingStrategy,
362
                        AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
363
                        AnnotationValueFilter.Factory annotationValueFilterFactory,
364
                        AnnotationRetention annotationRetention,
365
                        Implementation.Context.Factory implementationContextFactory,
366
                        MethodGraph.Compiler methodGraphCompiler,
367
                        InstrumentedType.Factory instrumentedTypeFactory,
368
                        TypeValidation typeValidation,
369
                        VisibilityBridgeStrategy visibilityBridgeStrategy,
370
                        AsmClassReader.Factory classReaderFactory,
371
                        AsmClassWriter.Factory classWriterFactory,
372
                        LatentMatcher<? super MethodDescription> ignoredMethods) {
1✔
373
        this.classFileVersion = classFileVersion;
1✔
374
        this.namingStrategy = namingStrategy;
1✔
375
        this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
1✔
376
        this.annotationValueFilterFactory = annotationValueFilterFactory;
1✔
377
        this.annotationRetention = annotationRetention;
1✔
378
        this.implementationContextFactory = implementationContextFactory;
1✔
379
        this.methodGraphCompiler = methodGraphCompiler;
1✔
380
        this.instrumentedTypeFactory = instrumentedTypeFactory;
1✔
381
        this.typeValidation = typeValidation;
1✔
382
        this.visibilityBridgeStrategy = visibilityBridgeStrategy;
1✔
383
        this.classReaderFactory = classReaderFactory;
1✔
384
        this.classWriterFactory = classWriterFactory;
1✔
385
        this.ignoredMethods = ignoredMethods;
1✔
386
    }
1✔
387

388
    /**
389
     * <p>
390
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
391
     * this interface type is created.
392
     * </p>
393
     * <p>
394
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type. Any constructor is implemented
395
     * to only invoke its super type constructor of equal signature. Another behavior can be specified by supplying an explicit
396
     * {@link ConstructorStrategy} by {@link ByteBuddy#subclass(Class, ConstructorStrategy)}.
397
     * </p>
398
     * <p>
399
     * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
400
     * </p>
401
     * <p>
402
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
403
     * types, a external cache or {@link TypeCache} should be used.
404
     * </p>
405
     *
406
     * @param superType The super class or interface type to extend.
407
     * @param <T>       A loaded type that the generated class is guaranteed to inherit.
408
     * @return A type builder for creating a new class extending the provided class or interface.
409
     */
410
    @SuppressWarnings("unchecked")
411
    public <T> DynamicType.Builder<T> subclass(Class<T> superType) {
412
        return (DynamicType.Builder<T>) subclass(TypeDescription.ForLoadedType.of(superType));
1✔
413
    }
414

415
    /**
416
     * <p>
417
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
418
     * this interface type is created.
419
     * </p>
420
     * <p>
421
     * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
422
     * </p>
423
     * <p>
424
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
425
     * types, a external cache or {@link TypeCache} should be used.
426
     * </p>
427
     *
428
     * @param superType           The super class or interface type to extend.
429
     * @param constructorStrategy A constructor strategy that determines the
430
     * @param <T>                 A loaded type that the generated class is guaranteed to inherit.
431
     * @return A type builder for creating a new class extending the provided class or interface.
432
     */
433
    @SuppressWarnings("unchecked")
434
    public <T> DynamicType.Builder<T> subclass(Class<T> superType, ConstructorStrategy constructorStrategy) {
435
        return (DynamicType.Builder<T>) subclass(TypeDescription.ForLoadedType.of(superType), constructorStrategy);
1✔
436
    }
437

438
    /**
439
     * <p>
440
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
441
     * this interface type is created.
442
     * </p>
443
     * <p>
444
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type. Any constructor is implemented
445
     * to only invoke its super type constructor of equal signature. Another behavior can be specified by supplying an explicit
446
     * {@link ConstructorStrategy} by {@link ByteBuddy#subclass(Type, ConstructorStrategy)}.
447
     * </p>
448
     * <p>
449
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
450
     * as raw types if they declare type variables.
451
     * </p>
452
     * <p>
453
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
454
     * types, a external cache or {@link TypeCache} should be used.
455
     * </p>
456
     *
457
     * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
458
     *                  variables that are referenced by the generic type must be declared by the generated subclass before creating
459
     *                  the type.
460
     * @return A type builder for creating a new class extending the provided class or interface.
461
     */
462
    public DynamicType.Builder<?> subclass(Type superType) {
463
        return subclass(TypeDefinition.Sort.describe(superType));
×
464
    }
465

466
    /**
467
     * <p>
468
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
469
     * this interface type is created.
470
     * </p>
471
     * <p>
472
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
473
     * as raw types if they declare type variables.
474
     * </p>
475
     * <p>
476
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
477
     * types, a external cache or {@link TypeCache} should be used.
478
     * </p>
479
     *
480
     * @param superType           The super class or interface type to extend. The type must be a raw type or parameterized
481
     *                            type. All type variables that are referenced by the generic type must be declared by the
482
     *                            generated subclass before creating the type.
483
     * @param constructorStrategy A constructor strategy that determines the
484
     * @return A type builder for creating a new class extending the provided class or interface.
485
     */
486
    public DynamicType.Builder<?> subclass(Type superType, ConstructorStrategy constructorStrategy) {
487
        return subclass(TypeDefinition.Sort.describe(superType), constructorStrategy);
×
488
    }
489

490
    /**
491
     * <p>
492
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
493
     * this interface type is created.
494
     * </p>
495
     * <p>
496
     * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type and sets them to be {@code public}.
497
     * Any constructor is implemented to only invoke its super type constructor of equal signature. Another behavior can be specified by
498
     * supplying an explicit {@link ConstructorStrategy} by {@link ByteBuddy#subclass(TypeDefinition, ConstructorStrategy)}.
499
     * </p>
500
     * <p>
501
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
502
     * as raw types if they declare type variables.
503
     * </p>
504
     * <p>
505
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
506
     * types, a external cache or {@link TypeCache} should be used.
507
     * </p>
508
     *
509
     * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
510
     *                  variables that are referenced by the generic type must be declared by the generated subclass before creating
511
     *                  the type.
512
     * @return A type builder for creating a new class extending the provided class or interface.
513
     */
514
    public DynamicType.Builder<?> subclass(TypeDefinition superType) {
515
        return subclass(superType, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING);
1✔
516
    }
517

518
    /**
519
     * <p>
520
     * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
521
     * this interface type is created.
522
     * </p>
523
     * <p>
524
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
525
     * as raw types if they declare type variables.
526
     * </p>
527
     * <p>
528
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
529
     * types, a external cache or {@link TypeCache} should be used.
530
     * </p>
531
     *
532
     * @param superType           The super class or interface type to extend. The type must be a raw type or parameterized
533
     *                            type. All type variables that are referenced by the generic type must be declared by the
534
     *                            generated subclass before creating the type.
535
     * @param constructorStrategy A constructor strategy that determines the
536
     * @return A type builder for creating a new class extending the provided class or interface.
537
     */
538
    public DynamicType.Builder<?> subclass(TypeDefinition superType, ConstructorStrategy constructorStrategy) {
539
        TypeDescription.Generic actualSuperType;
540
        TypeList.Generic interfaceTypes;
541
        if (superType.isPrimitive() || superType.isArray() || superType.isFinal()) {
1✔
542
            throw new IllegalArgumentException("Cannot subclass primitive, array or final types: " + superType);
1✔
543
        } else if (superType.isInterface()) {
1✔
544
            actualSuperType = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class);
1✔
545
            interfaceTypes = new TypeList.Generic.Explicit(superType);
1✔
546
        } else {
547
            actualSuperType = superType.asGenericType();
1✔
548
            interfaceTypes = new TypeList.Generic.Empty();
1✔
549
        }
550
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(namingStrategy.subclass(superType.asGenericType()),
1✔
551
                ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.PLAIN).resolve(superType.getModifiers()),
1✔
552
                actualSuperType).withInterfaces(interfaceTypes),
1✔
553
                classFileVersion,
554
                auxiliaryTypeNamingStrategy,
555
                annotationValueFilterFactory,
556
                annotationRetention,
557
                implementationContextFactory,
558
                methodGraphCompiler,
559
                typeValidation,
560
                visibilityBridgeStrategy,
561
                classReaderFactory,
562
                classWriterFactory,
563
                ignoredMethods,
564
                constructorStrategy);
565
    }
566

567
    /**
568
     * <p>
569
     * Creates a new, plain interface type.
570
     * </p>
571
     * <p>
572
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
573
     * types, a external cache or {@link TypeCache} should be used.
574
     * </p>
575
     *
576
     * @return A type builder that creates a new interface type.
577
     */
578
    public DynamicType.Builder<?> makeInterface() {
579
        return makeInterface(Collections.<TypeDescription>emptyList());
1✔
580
    }
581

582
    /**
583
     * <p>
584
     * Creates a new interface type that extends the provided interface.
585
     * </p>
586
     * <p>
587
     * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
588
     * </p>
589
     * <p>
590
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
591
     * types, a external cache or {@link TypeCache} should be used.
592
     * </p>
593
     *
594
     * @param interfaceType An interface type that the generated interface implements.
595
     * @param <T>           A loaded type that the generated interface is guaranteed to inherit.
596
     * @return A type builder that creates a new interface type.
597
     */
598
    @SuppressWarnings("unchecked")
599
    public <T> DynamicType.Builder<T> makeInterface(Class<T> interfaceType) {
600
        return (DynamicType.Builder<T>) makeInterface(Collections.<Type>singletonList(interfaceType));
1✔
601
    }
602

603
    /**
604
     * <p>
605
     * Creates a new interface type that extends the provided interface.
606
     * </p>
607
     * <p>
608
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
609
     * as raw types if they declare type variables or an owner 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
     * @param interfaceType The interface types to implement. The types must be raw or parameterized types. All type
617
     *                      variables that are referenced by a parameterized type must be declared by the generated
618
     *                      subclass before creating the type.
619
     * @return A type builder that creates a new interface type.
620
     */
621
    public DynamicType.Builder<?> makeInterface(Type... interfaceType) {
622
        return makeInterface(Arrays.asList(interfaceType));
×
623
    }
624

625
    /**
626
     * <p>
627
     * Creates a new interface type that extends the provided interface.
628
     * </p>
629
     * <p>
630
     * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
631
     * as raw types if they declare type variables or an owner type.
632
     * </p>
633
     * <p>
634
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
635
     * types, a external cache or {@link TypeCache} should be used.
636
     * </p>
637
     *
638
     * @param interfaceTypes The interface types to implement. The types must be raw or parameterized types. All
639
     *                       type variables that are referenced by a parameterized type must be declared by the
640
     *                       generated subclass before creating the type.
641
     * @return A type builder that creates a new interface type.
642
     */
643
    public DynamicType.Builder<?> makeInterface(List<? extends Type> interfaceTypes) {
644
        return makeInterface(new TypeList.Generic.ForLoadedTypes(interfaceTypes));
1✔
645
    }
646

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

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

691
    /**
692
     * <p>
693
     * Creates a new package definition. Package definitions are defined by classes named {@code package-info}
694
     * without any methods or fields but permit annotations. Any field or method definition will cause an
695
     * {@link IllegalStateException} to be thrown when the type is created.
696
     * </p>
697
     * <p>
698
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
699
     * types, a external cache or {@link TypeCache} should be used.
700
     * </p>
701
     *
702
     * @param name The fully qualified name of the package.
703
     * @return A type builder that creates a {@code package-info} class file.
704
     */
705
    public DynamicType.Builder<?> makePackage(String name) {
706
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(name + "." + PackageDescription.PACKAGE_CLASS_NAME,
1✔
707
                PackageDescription.PACKAGE_MODIFIERS,
708
                TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)),
1✔
709
                classFileVersion,
710
                auxiliaryTypeNamingStrategy,
711
                annotationValueFilterFactory,
712
                annotationRetention,
713
                implementationContextFactory,
714
                methodGraphCompiler,
715
                typeValidation,
716
                visibilityBridgeStrategy,
717
                classReaderFactory,
718
                classWriterFactory,
719
                ignoredMethods,
720
                ConstructorStrategy.Default.NO_CONSTRUCTORS);
721
    }
722

723
    /**
724
     * Creates a new Java record. This builder automatically defines fields for record members, standard accessors and a record constructor for any
725
     * defined record component.
726
     *
727
     * @return A dynamic type builder that creates a record.
728
     */
729
    public DynamicType.Builder<?> makeRecord() {
730
        TypeDescription.Generic record = InstrumentedType.Default.of(JavaType.RECORD.getTypeStub().getName(), TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class), Visibility.PUBLIC)
1✔
731
                .withMethod(new MethodDescription.Token(Opcodes.ACC_PROTECTED))
1✔
732
                .withMethod(new MethodDescription.Token("hashCode",
1✔
733
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
734
                        TypeDescription.ForLoadedType.of(int.class).asGenericType()))
1✔
735
                .withMethod(new MethodDescription.Token("equals",
1✔
736
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
737
                        TypeDescription.ForLoadedType.of(boolean.class).asGenericType(),
1✔
738
                        Collections.singletonList(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class))))
1✔
739
                .withMethod(new MethodDescription.Token("toString",
1✔
740
                        Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
741
                        TypeDescription.ForLoadedType.of(String.class).asGenericType()))
1✔
742
                .asGenericType();
1✔
743
        return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(namingStrategy.subclass(record), Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, record).withRecord(true),
1✔
744
                classFileVersion,
745
                auxiliaryTypeNamingStrategy,
746
                annotationValueFilterFactory,
747
                annotationRetention,
748
                implementationContextFactory,
749
                methodGraphCompiler,
750
                typeValidation,
751
                visibilityBridgeStrategy,
752
                classReaderFactory,
753
                classWriterFactory,
754
                ignoredMethods,
755
                RecordConstructorStrategy.INSTANCE)
756
                .method(isHashCode()).intercept(RecordObjectMethod.HASH_CODE)
1✔
757
                .method(isEquals()).intercept(RecordObjectMethod.EQUALS)
1✔
758
                .method(isToString()).intercept(RecordObjectMethod.TO_STRING);
1✔
759
    }
760

761
    /**
762
     * <p>
763
     * Creates a new {@link Annotation} type. Annotation properties are implemented as non-static, public methods with the
764
     * property type being defined as the return type.
765
     * </p>
766
     * <p>
767
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
768
     * types, a external cache or {@link TypeCache} should be used.
769
     * </p>
770
     *
771
     * @return A type builder that creates a new {@link Annotation} type.
772
     */
773
    public DynamicType.Builder<? extends Annotation> makeAnnotation() {
774
        return new SubclassDynamicTypeBuilder<Annotation>(instrumentedTypeFactory.subclass(namingStrategy.subclass(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Annotation.class)),
1✔
775
                ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.ANNOTATION).resolve(),
1✔
776
                TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class)).withInterfaces(new TypeList.Generic.Explicit(TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Annotation.class))),
1✔
777
                classFileVersion,
778
                auxiliaryTypeNamingStrategy,
779
                annotationValueFilterFactory,
780
                annotationRetention,
781
                implementationContextFactory,
782
                methodGraphCompiler,
783
                typeValidation,
784
                visibilityBridgeStrategy,
785
                classReaderFactory,
786
                classWriterFactory,
787
                ignoredMethods,
788
                ConstructorStrategy.Default.NO_CONSTRUCTORS);
789
    }
790

791
    /**
792
     * <p>
793
     * Creates a new {@link Enum} type.
794
     * </p>
795
     * <p>
796
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
797
     * types, a external cache or {@link TypeCache} should be used.
798
     * </p>
799
     *
800
     * @param value The names of the type's enumeration constants
801
     * @return A type builder for creating an enumeration type.
802
     */
803
    public DynamicType.Builder<? extends Enum<?>> makeEnumeration(String... value) {
804
        return makeEnumeration(Arrays.asList(value));
1✔
805
    }
806

807
    /**
808
     * <p>
809
     * Creates a new {@link Enum} type.
810
     * </p>
811
     * <p>
812
     * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
813
     * types, a external cache or {@link TypeCache} should be used.
814
     * </p>
815
     *
816
     * @param values The names of the type's enumeration constants
817
     * @return A type builder for creating an enumeration type.
818
     */
819
    public DynamicType.Builder<? extends Enum<?>> makeEnumeration(Collection<? extends String> values) {
820
        if (values.isEmpty()) {
1✔
821
            throw new IllegalArgumentException("Require at least one enumeration constant");
1✔
822
        }
823
        TypeDescription.Generic enumType = TypeDescription.Generic.Builder.parameterizedType(Enum.class, TargetType.class).build();
1✔
824
        return new SubclassDynamicTypeBuilder<Enum<?>>(instrumentedTypeFactory.subclass(namingStrategy.subclass(enumType),
1✔
825
                ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL, EnumerationState.ENUMERATION).resolve(),
1✔
826
                enumType),
827
                classFileVersion,
828
                auxiliaryTypeNamingStrategy,
829
                annotationValueFilterFactory,
830
                annotationRetention,
831
                implementationContextFactory,
832
                methodGraphCompiler,
833
                typeValidation,
834
                visibilityBridgeStrategy,
835
                classReaderFactory,
836
                classWriterFactory,
837
                ignoredMethods,
838
                ConstructorStrategy.Default.NO_CONSTRUCTORS)
839
                .defineConstructor(Visibility.PRIVATE).withParameters(String.class, int.class)
1✔
840
                .intercept(SuperMethodCall.INSTANCE)
1✔
841
                .defineMethod(EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME,
1✔
842
                        TargetType.class,
843
                        Visibility.PUBLIC, Ownership.STATIC).withParameters(String.class)
1✔
844
                .intercept(MethodCall.invoke(enumType.getDeclaredMethods()
1✔
845
                                .filter(named(EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME).and(takesArguments(Class.class, String.class))).getOnly())
1✔
846
                        .withOwnType().withArgument(0)
1✔
847
                        .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC))
1✔
848
                .defineMethod(EnumerationImplementation.ENUM_VALUES_METHOD_NAME,
1✔
849
                        TargetType[].class,
850
                        Visibility.PUBLIC, Ownership.STATIC)
851
                .intercept(new EnumerationImplementation(new ArrayList<String>(values)));
1✔
852
    }
853

854
    /**
855
     * <p>
856
     * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
857
     * by the new implementation.
858
     * </p>
859
     * <p>
860
     * The class file of the redefined type is located by querying the redefined type's class loader by name. For specifying an
861
     * alternative {@link ClassFileLocator}, use {@link ByteBuddy#redefine(Class, ClassFileLocator)}.
862
     * </p>
863
     * <p>
864
     * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
865
     * 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.
866
     * 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
867
     * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
868
     * where the class initializer is retained <i>as is</i>.
869
     * </p>
870
     *
871
     * @param type The type that is being redefined.
872
     * @param <T>  The loaded type of the redefined type.
873
     * @return A type builder for redefining the provided type.
874
     */
875
    public <T> DynamicType.Builder<T> redefine(Class<T> type) {
876
        return redefine(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
877
    }
878

879
    /**
880
     * <p>
881
     * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
882
     * by the new implementation.
883
     * </p>
884
     * <p>
885
     * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
886
     * 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.
887
     * 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
888
     * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
889
     * where the class initializer is retained <i>as is</i>.
890
     * </p>
891
     *
892
     * @param type             The type that is being redefined.
893
     * @param classFileLocator The class file locator that is queried for the redefined type's class file.
894
     * @param <T>              The loaded type of the redefined type.
895
     * @return A type builder for redefining the provided type.
896
     */
897
    public <T> DynamicType.Builder<T> redefine(Class<T> type, ClassFileLocator classFileLocator) {
898
        return redefine(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
899
    }
900

901
    /**
902
     * <p>
903
     * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
904
     * by the new implementation.
905
     * </p>
906
     * <p>
907
     * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
908
     * 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.
909
     * 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
910
     * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
911
     * where the class initializer is retained <i>as is</i>.
912
     * </p>
913
     *
914
     * @param type             The type that is being redefined.
915
     * @param classFileLocator The class file locator that is queried for the redefined type's class file.
916
     * @param <T>              The loaded type of the redefined type.
917
     * @return A type builder for redefining the provided type.
918
     */
919
    public <T> DynamicType.Builder<T> redefine(TypeDescription type, ClassFileLocator classFileLocator) {
920
        if (type.isArray() || type.isPrimitive()) {
1✔
921
            throw new IllegalArgumentException("Cannot redefine array or primitive type: " + type);
×
922
        }
923
        return new RedefinitionDynamicTypeBuilder<T>(instrumentedTypeFactory.represent(type),
1✔
924
                classFileVersion,
925
                auxiliaryTypeNamingStrategy,
926
                annotationValueFilterFactory,
927
                annotationRetention,
928
                implementationContextFactory,
929
                methodGraphCompiler,
930
                typeValidation,
931
                visibilityBridgeStrategy,
932
                classReaderFactory,
933
                classWriterFactory,
934
                ignoredMethods,
935
                type,
936
                classFileLocator);
937
    }
938

939
    /**
940
     * <p>
941
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
942
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
943
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
944
     * </p>
945
     * <p>
946
     * The class file of the rebased type is located by querying the rebased type's class loader by name. For specifying an
947
     * alternative {@link ClassFileLocator}, use {@link ByteBuddy#redefine(Class, ClassFileLocator)}.
948
     * </p>
949
     *
950
     * @param type The type that is being rebased.
951
     * @param <T>  The loaded type of the rebased type.
952
     * @return A type builder for rebasing the provided type.
953
     */
954
    public <T> DynamicType.Builder<T> rebase(Class<T> type) {
955
        return rebase(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
956
    }
957

958
    /**
959
     * <p>
960
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
961
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
962
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
963
     * </p>
964
     * <p>
965
     * When a method is rebased, the original method is copied into a new method with a different name. These names are
966
     * generated automatically by Byte Buddy unless a {@link MethodNameTransformer} is specified explicitly.
967
     * Use {@link ByteBuddy#rebase(Class, ClassFileLocator, MethodNameTransformer)} for doing so.
968
     * </p>
969
     *
970
     * @param type             The type that is being rebased.
971
     * @param classFileLocator The class file locator that is queried for the rebased type's class file.
972
     * @param <T>              The loaded type of the rebased type.
973
     * @return A type builder for rebasing the provided type.
974
     */
975
    public <T> DynamicType.Builder<T> rebase(Class<T> type, ClassFileLocator classFileLocator) {
976
        return rebase(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
977
    }
978

979
    /**
980
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
981
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
982
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
983
     *
984
     * @param type                  The type that is being rebased.
985
     * @param classFileLocator      The class file locator that is queried for the rebased type's class file.
986
     * @param methodNameTransformer The method name transformer for renaming a method that is rebased.
987
     * @param <T>                   The loaded type of the rebased type.
988
     * @return A type builder for rebasing the provided type.
989
     */
990
    public <T> DynamicType.Builder<T> rebase(Class<T> type, ClassFileLocator classFileLocator, MethodNameTransformer methodNameTransformer) {
991
        return rebase(TypeDescription.ForLoadedType.of(type), classFileLocator, methodNameTransformer);
×
992
    }
993

994
    /**
995
     * <p>
996
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
997
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
998
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
999
     * </p>
1000
     * <p>
1001
     * When a method is rebased, the original method is copied into a new method with a different name. These names are
1002
     * generated automatically by Byte Buddy unless a {@link MethodNameTransformer} is specified explicitly.
1003
     * Use {@link ByteBuddy#rebase(TypeDescription, ClassFileLocator, MethodNameTransformer)} for doing so.
1004
     * </p>
1005
     *
1006
     * @param type             The type that is being rebased.
1007
     * @param classFileLocator The class file locator that is queried for the rebased type's class file.
1008
     * @param <T>              The loaded type of the rebased type.
1009
     * @return A type builder for rebasing the provided type.
1010
     */
1011
    public <T> DynamicType.Builder<T> rebase(TypeDescription type, ClassFileLocator classFileLocator) {
1012
        return rebase(type, classFileLocator, MethodNameTransformer.Suffixing.withRandomSuffix());
1✔
1013
    }
1014

1015
    /**
1016
     * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
1017
     * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
1018
     * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
1019
     *
1020
     * @param type                  The type that is being rebased.
1021
     * @param classFileLocator      The class file locator that is queried for the rebased type's class file.
1022
     * @param methodNameTransformer The method name transformer for renaming a method that is rebased.
1023
     * @param <T>                   The loaded type of the rebased type.
1024
     * @return A type builder for rebasing the provided type.
1025
     */
1026
    public <T> DynamicType.Builder<T> rebase(TypeDescription type, ClassFileLocator classFileLocator, MethodNameTransformer methodNameTransformer) {
1027
        if (type.isArray() || type.isPrimitive()) {
1✔
1028
            throw new IllegalArgumentException("Cannot rebase array or primitive type: " + type);
×
1029
        }
1030
        return new RebaseDynamicTypeBuilder<T>(instrumentedTypeFactory.represent(type),
1✔
1031
                classFileVersion,
1032
                auxiliaryTypeNamingStrategy,
1033
                annotationValueFilterFactory,
1034
                annotationRetention,
1035
                implementationContextFactory,
1036
                methodGraphCompiler,
1037
                typeValidation,
1038
                visibilityBridgeStrategy,
1039
                classReaderFactory,
1040
                classWriterFactory,
1041
                ignoredMethods,
1042
                type,
1043
                classFileLocator,
1044
                methodNameTransformer);
1045
    }
1046

1047
    /**
1048
     * Rebases a package. This offers an opportunity to add annotations to the package definition. Packages are defined
1049
     * by classes named {@code package-info} without any methods or fields but permit annotations. Any field or method
1050
     * definition will cause an {@link IllegalStateException} to be thrown when the type is created.
1051
     *
1052
     * @param aPackage         The package that is being rebased.
1053
     * @param classFileLocator The class file locator to use for locating the package's class file.
1054
     * @return A type builder for rebasing the given package.
1055
     */
1056
    public DynamicType.Builder<?> rebase(Package aPackage, ClassFileLocator classFileLocator) {
1057
        return rebase(new PackageDescription.ForLoadedPackage(aPackage), classFileLocator);
1✔
1058
    }
1059

1060
    /**
1061
     * Rebases a package. This offers an opportunity to add annotations to the package definition. Packages are defined
1062
     * by classes named {@code package-info} without any methods or fields but permit annotations. Any field or method
1063
     * definition will cause an {@link IllegalStateException} to be thrown when the type is created.
1064
     *
1065
     * @param aPackage         The package that is being rebased.
1066
     * @param classFileLocator The class file locator to use for locating the package's class file.
1067
     * @return A type builder for rebasing the given package.
1068
     */
1069
    public DynamicType.Builder<?> rebase(PackageDescription aPackage, ClassFileLocator classFileLocator) {
1070
        return rebase(new TypeDescription.ForPackageDescription(aPackage), classFileLocator);
1✔
1071
    }
1072

1073
    /**
1074
     * <p>
1075
     * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
1076
     * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
1077
     * when implementing a Java agent that only applies ASM-based code changes.
1078
     * </p>
1079
     * <p>
1080
     * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
1081
     * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
1082
     * {@link Implementation.Context.Factory} that does not attempt any type transformation.
1083
     * </p>
1084
     *
1085
     * @param type The type to decorate.
1086
     * @param <T>  The loaded type of the decorated type.
1087
     * @return A type builder for decorating the provided type.
1088
     */
1089
    public <T> DynamicType.Builder<T> decorate(Class<T> type) {
1090
        return decorate(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
1✔
1091
    }
1092

1093
    /**
1094
     * <p>
1095
     * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
1096
     * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
1097
     * when implementing a Java agent that only applies ASM-based code changes.
1098
     * </p>
1099
     * <p>
1100
     * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
1101
     * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
1102
     * {@link Implementation.Context.Factory} that does not attempt any type transformation.
1103
     * </p>
1104
     *
1105
     * @param type             The type to decorate.
1106
     * @param classFileLocator The class file locator to use.
1107
     * @param <T>              The loaded type of the decorated type.
1108
     * @return A type builder for decorating the provided type.
1109
     */
1110
    public <T> DynamicType.Builder<T> decorate(Class<T> type, ClassFileLocator classFileLocator) {
1111
        return decorate(TypeDescription.ForLoadedType.of(type), classFileLocator);
1✔
1112
    }
1113

1114
    /**
1115
     * <p>
1116
     * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
1117
     * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
1118
     * when implementing a Java agent that only applies ASM-based code changes.
1119
     * </p>
1120
     * <p>
1121
     * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
1122
     * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
1123
     * {@link Implementation.Context.Factory} that does not attempt any type transformation.
1124
     * </p>
1125
     *
1126
     * @param type             The type to decorate.
1127
     * @param classFileLocator The class file locator to use.
1128
     * @param <T>              The loaded type of the decorated type.
1129
     * @return A type builder for decorating the provided type.
1130
     */
1131
    public <T> DynamicType.Builder<T> decorate(TypeDescription type, ClassFileLocator classFileLocator) {
1132
        if (type.isArray() || type.isPrimitive()) {
1✔
1133
            throw new IllegalArgumentException("Cannot decorate array or primitive type: " + type);
×
1134
        }
1135
        return new DecoratingDynamicTypeBuilder<T>(type,
1✔
1136
                classFileVersion,
1137
                auxiliaryTypeNamingStrategy,
1138
                annotationValueFilterFactory,
1139
                annotationRetention,
1140
                implementationContextFactory,
1141
                methodGraphCompiler,
1142
                typeValidation,
1143
                classReaderFactory,
1144
                classWriterFactory,
1145
                ignoredMethods,
1146
                classFileLocator);
1147
    }
1148

1149
    /**
1150
     * Creates a new configuration where all class files that are not based on an existing class file are created
1151
     * using the supplied class file version. When creating a Byte Buddy instance by {@link ByteBuddy#ByteBuddy()}, the class
1152
     * file version is detected automatically. If the class file version is known before creating a Byte Buddy instance, the
1153
     * {@link ByteBuddy#ByteBuddy(ClassFileVersion)} constructor should be used.
1154
     *
1155
     * @param classFileVersion The class file version to use for types that are not based on an existing class file.
1156
     * @return A new Byte Buddy instance that uses the supplied class file version.
1157
     */
1158
    public ByteBuddy with(ClassFileVersion classFileVersion) {
1159
        return new ByteBuddy(classFileVersion,
×
1160
                namingStrategy,
1161
                auxiliaryTypeNamingStrategy,
1162
                annotationValueFilterFactory,
1163
                annotationRetention,
1164
                implementationContextFactory,
1165
                methodGraphCompiler,
1166
                instrumentedTypeFactory,
1167
                typeValidation,
1168
                visibilityBridgeStrategy,
1169
                classReaderFactory,
1170
                classWriterFactory,
1171
                ignoredMethods);
1172
    }
1173

1174
    /**
1175
     * Creates a new configuration where new types are named by applying the given naming strategy. By default, Byte Buddy
1176
     * simply retains the name of rebased and redefined types but adds a random suffix to the name of created subclasses or
1177
     * -interfaces. If a type is defined within the {@code java.*} namespace, Byte Buddy also adds a suffix to the generated
1178
     * class because this namespace is only available for the bootstrap class loader.
1179
     *
1180
     * @param namingStrategy The naming strategy to apply when creating a new dynamic type.
1181
     * @return A new Byte Buddy instance that uses the supplied naming strategy.
1182
     */
1183
    public ByteBuddy with(NamingStrategy namingStrategy) {
1184
        return new ByteBuddy(classFileVersion,
1✔
1185
                namingStrategy,
1186
                auxiliaryTypeNamingStrategy,
1187
                annotationValueFilterFactory,
1188
                annotationRetention,
1189
                implementationContextFactory,
1190
                methodGraphCompiler,
1191
                instrumentedTypeFactory,
1192
                typeValidation,
1193
                visibilityBridgeStrategy,
1194
                classReaderFactory,
1195
                classWriterFactory,
1196
                ignoredMethods);
1197
    }
1198

1199
    /**
1200
     * Creates a new configuration where auxiliary types are named by applying the given naming strategy. Auxiliary types
1201
     * are helper types that might be required for implementing certain {@link Implementation}s. By default, Byte Buddy
1202
     * adds a random suffix to the instrumented type's name when naming its auxiliary types.
1203
     *
1204
     * @param auxiliaryTypeNamingStrategy The naming strategy to apply when creating a new auxiliary type.
1205
     * @return A new Byte Buddy instance that uses the supplied naming strategy for auxiliary types.
1206
     */
1207
    public ByteBuddy with(AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy) {
1208
        return new ByteBuddy(classFileVersion,
×
1209
                namingStrategy,
1210
                auxiliaryTypeNamingStrategy,
1211
                annotationValueFilterFactory,
1212
                annotationRetention,
1213
                implementationContextFactory,
1214
                methodGraphCompiler,
1215
                instrumentedTypeFactory,
1216
                typeValidation,
1217
                visibilityBridgeStrategy,
1218
                classReaderFactory,
1219
                classWriterFactory,
1220
                ignoredMethods);
1221
    }
1222

1223
    /**
1224
     * Creates a new configuration where annotation values are written according to the given filter factory. Using
1225
     * a filter factory, it is for example possible not to include certain values into a class file such that the
1226
     * runtime returns an annotation type's default value. By default, Byte Buddy includes all values into a class file,
1227
     * also such values for which a default value exists.
1228
     *
1229
     * @param annotationValueFilterFactory The annotation value filter factory to use.
1230
     * @return A new Byte Buddy instance that uses the supplied annotation value filter factory.
1231
     */
1232
    public ByteBuddy with(AnnotationValueFilter.Factory annotationValueFilterFactory) {
1233
        return new ByteBuddy(classFileVersion,
×
1234
                namingStrategy,
1235
                auxiliaryTypeNamingStrategy,
1236
                annotationValueFilterFactory,
1237
                annotationRetention,
1238
                implementationContextFactory,
1239
                methodGraphCompiler,
1240
                instrumentedTypeFactory,
1241
                typeValidation,
1242
                visibilityBridgeStrategy,
1243
                classReaderFactory,
1244
                classWriterFactory,
1245
                ignoredMethods);
1246
    }
1247

1248
    /**
1249
     * <p>
1250
     * Creates a new configuration where annotations that are found in an existing class file are or are not preserved
1251
     * in the format they are discovered, i.e. rewritten in the format they were already present in the class file.
1252
     * By default, Byte Buddy retains annotations when a class is rebased or redefined.
1253
     * </p>
1254
     * <p>
1255
     * <b>Warning</b>: Retaining annotations can cause problems when annotations of a field or method are added based
1256
     * on the annotations of a matched method. Doing so, Byte Buddy might write the annotations of the field or method
1257
     * explicitly to a class file while simultaneously retaining the existing annotation what results in duplicates.
1258
     * When matching fields or methods while adding annotations, disabling annotation retention might be required.
1259
     * </p>
1260
     *
1261
     * @param annotationRetention The annotation retention strategy to use.
1262
     * @return A new Byte Buddy instance that uses the supplied annotation retention strategy.
1263
     */
1264
    public ByteBuddy with(AnnotationRetention annotationRetention) {
1265
        return new ByteBuddy(classFileVersion,
1✔
1266
                namingStrategy,
1267
                auxiliaryTypeNamingStrategy,
1268
                annotationValueFilterFactory,
1269
                annotationRetention,
1270
                implementationContextFactory,
1271
                methodGraphCompiler,
1272
                instrumentedTypeFactory,
1273
                typeValidation,
1274
                visibilityBridgeStrategy,
1275
                classReaderFactory,
1276
                classWriterFactory,
1277
                ignoredMethods);
1278
    }
1279

1280
    /**
1281
     * Creates a new configuration where the {@link net.bytebuddy.implementation.Implementation.Context} of any created
1282
     * type is a product of the given implementation context factory. An implementation context might imply unwanted
1283
     * side-effects, for example, the creation of an additional synthetic methods in order to support specific features
1284
     * for realizing an {@link Implementation}. By default, Byte Buddy supplies a factory that enables all features. When
1285
     * redefining a loaded class, it is however required by the JVM that no additional members are added such that a
1286
     * {@link net.bytebuddy.implementation.Implementation.Context.Disabled} factory might be more appropriate.
1287
     *
1288
     * @param implementationContextFactory The implementation context factory to use for defining an instrumented type.
1289
     * @return A new Byte Buddy instance that uses the supplied implementation context factory.
1290
     */
1291
    public ByteBuddy with(Implementation.Context.Factory implementationContextFactory) {
1292
        return new ByteBuddy(classFileVersion,
1✔
1293
                namingStrategy,
1294
                auxiliaryTypeNamingStrategy,
1295
                annotationValueFilterFactory,
1296
                annotationRetention,
1297
                implementationContextFactory,
1298
                methodGraphCompiler,
1299
                instrumentedTypeFactory,
1300
                typeValidation,
1301
                visibilityBridgeStrategy,
1302
                classReaderFactory,
1303
                classWriterFactory,
1304
                ignoredMethods);
1305
    }
1306

1307
    /**
1308
     * Creates a new configuration where the {@link MethodGraph.Compiler} is used for creating a {@link MethodGraph}
1309
     * of the instrumented type. A method graph is a representation of a type's virtual methods, including all information
1310
     * on bridge methods that are inserted by the Java compiler. Creating a method graph is a rather expensive operation
1311
     * and more efficient strategies might exist for certain types or ava types that are created by alternative JVM
1312
     * languages. By default, a general purpose method graph compiler is used that uses the information that is exposed
1313
     * by the generic type information that is embedded in any class file.
1314
     *
1315
     * @param methodGraphCompiler The method graph compiler to use for analyzing the instrumented type.
1316
     * @return A new Byte Buddy instance that uses the supplied method graph compiler.
1317
     */
1318
    public ByteBuddy with(MethodGraph.Compiler methodGraphCompiler) {
1319
        return new ByteBuddy(classFileVersion,
1✔
1320
                namingStrategy,
1321
                auxiliaryTypeNamingStrategy,
1322
                annotationValueFilterFactory,
1323
                annotationRetention,
1324
                implementationContextFactory,
1325
                methodGraphCompiler,
1326
                instrumentedTypeFactory,
1327
                typeValidation,
1328
                visibilityBridgeStrategy,
1329
                classReaderFactory,
1330
                classWriterFactory,
1331
                ignoredMethods);
1332
    }
1333

1334
    /**
1335
     * Configures Byte Buddy to use the specified factory for creating {@link InstrumentedType}s. Doing so, more efficient
1336
     * representations can be chosen when only certain operations are required. By default, all operations are supported.
1337
     *
1338
     * @param instrumentedTypeFactory The factory to use when creating instrumented types.
1339
     * @return A new Byte Buddy instance that uses the supplied factory for creating instrumented types.
1340
     */
1341
    public ByteBuddy with(InstrumentedType.Factory instrumentedTypeFactory) {
1342
        return new ByteBuddy(classFileVersion,
1✔
1343
                namingStrategy,
1344
                auxiliaryTypeNamingStrategy,
1345
                annotationValueFilterFactory,
1346
                annotationRetention,
1347
                implementationContextFactory,
1348
                methodGraphCompiler,
1349
                instrumentedTypeFactory,
1350
                typeValidation,
1351
                visibilityBridgeStrategy,
1352
                classReaderFactory,
1353
                classWriterFactory,
1354
                ignoredMethods);
1355
    }
1356

1357
    /**
1358
     * Creates a new configuration that applies the supplied type validation. By default, explicitly type validation is applied
1359
     * by Byte Buddy but it might be disabled for performance reason or for voluntarily creating illegal types. The Java virtual
1360
     * machine applies its own type validation where some {@link Error} is thrown if a type is invalid, while Byte Buddy throws
1361
     * some {@link RuntimeException}.
1362
     *
1363
     * @param typeValidation The type validation to apply during type creation.
1364
     * @return A new Byte Buddy instance that applies the supplied type validation.
1365
     */
1366
    public ByteBuddy with(TypeValidation typeValidation) {
1367
        return new ByteBuddy(classFileVersion,
1✔
1368
                namingStrategy,
1369
                auxiliaryTypeNamingStrategy,
1370
                annotationValueFilterFactory,
1371
                annotationRetention,
1372
                implementationContextFactory,
1373
                methodGraphCompiler,
1374
                instrumentedTypeFactory,
1375
                typeValidation,
1376
                visibilityBridgeStrategy,
1377
                classReaderFactory,
1378
                classWriterFactory,
1379
                ignoredMethods);
1380
    }
1381

1382
    /**
1383
     * Creates a new configuration that applies the supplied visibility bridge strategy. By default, visibility bridges
1384
     * are create for all methods for which a visibility bridge is normally necessary.
1385
     *
1386
     * @param visibilityBridgeStrategy The visibility bridge strategy to apply.
1387
     * @return A new Byte Buddy instance that applies the supplied visibility bridge strategy.
1388
     */
1389
    public ByteBuddy with(VisibilityBridgeStrategy visibilityBridgeStrategy) {
1390
        return new ByteBuddy(classFileVersion,
1✔
1391
                namingStrategy,
1392
                auxiliaryTypeNamingStrategy,
1393
                annotationValueFilterFactory,
1394
                annotationRetention,
1395
                implementationContextFactory,
1396
                methodGraphCompiler,
1397
                instrumentedTypeFactory,
1398
                typeValidation,
1399
                visibilityBridgeStrategy,
1400
                classReaderFactory,
1401
                classWriterFactory,
1402
                ignoredMethods);
1403
    }
1404

1405
    /**
1406
     * Creates a new configuration that applies the supplied class writer strategy. By default, the constant pool of redefined and retransformed
1407
     * classes is retained as most changes are additive and this retention improves performance.
1408
     *
1409
     * @param classWriterStrategy The class writer strategy to apply during type creation.
1410
     * @return A new Byte Buddy instance that applies the supplied class writer strategy.
1411
     * @deprecated Use {@link ByteBuddy#with(AsmClassWriter.Factory)}.
1412
     */
1413
    @Deprecated
1414
    public ByteBuddy with(ClassWriterStrategy classWriterStrategy) {
1415
        return new ByteBuddy(classFileVersion,
×
1416
                namingStrategy,
1417
                auxiliaryTypeNamingStrategy,
1418
                annotationValueFilterFactory,
1419
                annotationRetention,
1420
                implementationContextFactory,
1421
                methodGraphCompiler,
1422
                instrumentedTypeFactory,
1423
                typeValidation,
1424
                visibilityBridgeStrategy,
1425
                classReaderFactory,
1426
                new ClassWriterStrategy.Delegating(classWriterStrategy),
1427
                ignoredMethods);
1428
    }
1429

1430
    /**
1431
     * Creates a new configuration that applies the supplied class reader factory.
1432
     *
1433
     * @param classReaderFactory The class reader factory to apply during type creation.
1434
     * @return A new Byte Buddy instance that applies the supplied class reader factory.
1435
     */
1436
    public ByteBuddy with(AsmClassReader.Factory classReaderFactory) {
1437
        return new ByteBuddy(classFileVersion,
×
1438
                namingStrategy,
1439
                auxiliaryTypeNamingStrategy,
1440
                annotationValueFilterFactory,
1441
                annotationRetention,
1442
                implementationContextFactory,
1443
                methodGraphCompiler,
1444
                instrumentedTypeFactory,
1445
                typeValidation,
1446
                visibilityBridgeStrategy,
1447
                classReaderFactory,
1448
                classWriterFactory,
1449
                ignoredMethods);
1450
    }
1451

1452
    /**
1453
     * Creates a new configuration that applies the supplied class writer factory.
1454
     *
1455
     * @param classWriterFactory The class writer factory to apply during type creation.
1456
     * @return A new Byte Buddy instance that applies the supplied class writer factory.
1457
     */
1458
    public ByteBuddy with(AsmClassWriter.Factory classWriterFactory) {
1459
        return new ByteBuddy(classFileVersion,
×
1460
                namingStrategy,
1461
                auxiliaryTypeNamingStrategy,
1462
                annotationValueFilterFactory,
1463
                annotationRetention,
1464
                implementationContextFactory,
1465
                methodGraphCompiler,
1466
                instrumentedTypeFactory,
1467
                typeValidation,
1468
                visibilityBridgeStrategy,
1469
                classReaderFactory,
1470
                classWriterFactory,
1471
                ignoredMethods);
1472
    }
1473

1474
    /**
1475
     * Creates a new configuration that ignores any original {@link AsmClassReader} while creating classes.
1476
     *
1477
     * @return A new Byte Buddy instance that applies the supplied class writer factory.
1478
     */
1479
    public ByteBuddy withIgnoredClassReader() {
1480
        return new ByteBuddy(classFileVersion,
×
1481
                namingStrategy,
1482
                auxiliaryTypeNamingStrategy,
1483
                annotationValueFilterFactory,
1484
                annotationRetention,
1485
                implementationContextFactory,
1486
                methodGraphCompiler,
1487
                instrumentedTypeFactory,
1488
                typeValidation,
1489
                visibilityBridgeStrategy,
1490
                classReaderFactory,
1491
                new AsmClassWriter.Factory.Suppressing(classWriterFactory),
1492
                ignoredMethods);
1493
    }
1494

1495
    /**
1496
     * Creates a new configuration where any {@link MethodDescription} that matches the provided method matcher is excluded
1497
     * from instrumentation. Any previous matcher for ignored methods is replaced. By default, Byte Buddy ignores any
1498
     * synthetic method (bridge methods are handled automatically) and the {@link Object#finalize()} method.
1499
     *
1500
     * @param ignoredMethods A matcher for identifying methods to be excluded from instrumentation.
1501
     * @return A new Byte Buddy instance that excludes any method from instrumentation if it is matched by the supplied matcher.
1502
     */
1503
    @SuppressWarnings("overloads")
1504
    public ByteBuddy ignore(ElementMatcher<? super MethodDescription> ignoredMethods) {
1505
        return ignore(new LatentMatcher.Resolved<MethodDescription>(ignoredMethods));
1✔
1506
    }
1507

1508
    /**
1509
     * <p>
1510
     * Creates a new configuration where any {@link MethodDescription} that matches the provided method matcher is excluded
1511
     * from instrumentation. Any previous matcher for ignored methods is replaced. By default, Byte Buddy ignores any
1512
     * synthetic method (bridge methods are handled automatically) and the {@link Object#finalize()} method. Using a latent
1513
     * matcher gives opportunity to resolve an {@link ElementMatcher} based on the instrumented type before applying the matcher.
1514
     * </p>
1515
     *
1516
     * @param ignoredMethods A matcher for identifying methods to be excluded from instrumentation.
1517
     * @return A new Byte Buddy instance that excludes any method from instrumentation if it is matched by the supplied matcher.
1518
     */
1519
    @SuppressWarnings("overloads")
1520
    public ByteBuddy ignore(LatentMatcher<? super MethodDescription> ignoredMethods) {
1521
        return new ByteBuddy(classFileVersion,
1✔
1522
                namingStrategy,
1523
                auxiliaryTypeNamingStrategy,
1524
                annotationValueFilterFactory,
1525
                annotationRetention,
1526
                implementationContextFactory,
1527
                methodGraphCompiler,
1528
                instrumentedTypeFactory,
1529
                typeValidation,
1530
                visibilityBridgeStrategy,
1531
                classReaderFactory,
1532
                classWriterFactory,
1533
                ignoredMethods);
1534
    }
1535

1536
    /**
1537
     * An implementation fo the {@code values} method of an enumeration type.
1538
     */
1539
    @HashCodeAndEqualsPlugin.Enhance
1540
    protected static class EnumerationImplementation implements Implementation {
1541

1542
        /**
1543
         * The name of the {@link java.lang.Object#clone()} method.
1544
         */
1545
        protected static final String CLONE_METHOD_NAME = "clone";
1546

1547
        /**
1548
         * The name of the {@code valueOf} method that is defined for any enumeration.
1549
         */
1550
        protected static final String ENUM_VALUE_OF_METHOD_NAME = "valueOf";
1551

1552
        /**
1553
         * The name of the {@code values} method that is defined for any enumeration.
1554
         */
1555
        protected static final String ENUM_VALUES_METHOD_NAME = "values";
1556

1557
        /**
1558
         * The field modifiers to use for any field that is added to an enumeration.
1559
         */
1560
        private static final int ENUM_FIELD_MODIFIERS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC;
1561

1562
        /**
1563
         * The name of the field containing an array of all enumeration values.
1564
         */
1565
        private static final String ENUM_VALUES = "$VALUES";
1566

1567
        /**
1568
         * The names of the enumerations to define for the enumeration.
1569
         */
1570
        private final List<String> values;
1571

1572
        /**
1573
         * Creates a new implementation of an enumeration type.
1574
         *
1575
         * @param values The values of the enumeration.
1576
         */
1577
        protected EnumerationImplementation(List<String> values) {
1✔
1578
            this.values = values;
1✔
1579
        }
1✔
1580

1581
        /**
1582
         * {@inheritDoc}
1583
         */
1584
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
1585
            for (String value : values) {
1✔
1586
                instrumentedType = instrumentedType.withField(new FieldDescription.Token(value,
1✔
1587
                        ENUM_FIELD_MODIFIERS | Opcodes.ACC_ENUM,
1588
                        TargetType.DESCRIPTION.asGenericType()));
1✔
1589
            }
1✔
1590
            return instrumentedType
1✔
1591
                    .withField(new FieldDescription.Token(ENUM_VALUES,
1✔
1592
                            ENUM_FIELD_MODIFIERS | Opcodes.ACC_SYNTHETIC,
1593
                            TypeDescription.ArrayProjection.of(TargetType.DESCRIPTION).asGenericType()))
1✔
1594
                    .withInitializer(new InitializationAppender(values));
1✔
1595
        }
1596

1597
        /**
1598
         * {@inheritDoc}
1599
         */
1600
        public ByteCodeAppender appender(Target implementationTarget) {
1601
            return new ValuesMethodAppender(implementationTarget.getInstrumentedType());
1✔
1602
        }
1603

1604
        /**
1605
         * A byte code appender for the {@code values} method of any enumeration type.
1606
         */
1607
        @HashCodeAndEqualsPlugin.Enhance
1608
        protected static class ValuesMethodAppender implements ByteCodeAppender {
1609

1610
            /**
1611
             * The instrumented enumeration type.
1612
             */
1613
            private final TypeDescription instrumentedType;
1614

1615
            /**
1616
             * Creates a new appender for the {@code values} method.
1617
             *
1618
             * @param instrumentedType The instrumented enumeration type.
1619
             */
1620
            protected ValuesMethodAppender(TypeDescription instrumentedType) {
1✔
1621
                this.instrumentedType = instrumentedType;
1✔
1622
            }
1✔
1623

1624
            /**
1625
             * {@inheritDoc}
1626
             */
1627
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1628
                FieldDescription valuesField = instrumentedType.getDeclaredFields().filter(named(ENUM_VALUES)).getOnly();
1✔
1629
                MethodDescription cloneMethod = TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class).getDeclaredMethods().filter(named(CLONE_METHOD_NAME)).getOnly();
1✔
1630
                return new Size(new StackManipulation.Compound(
1✔
1631
                        FieldAccess.forField(valuesField).read(),
1✔
1632
                        MethodInvocation.invoke(cloneMethod).virtual(valuesField.getType().asErasure()),
1✔
1633
                        TypeCasting.to(valuesField.getType().asErasure()),
1✔
1634
                        MethodReturn.REFERENCE
1635
                ).apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
1636
            }
1637
        }
1638

1639
        /**
1640
         * A byte code appender for the type initializer of any enumeration type.
1641
         */
1642
        @HashCodeAndEqualsPlugin.Enhance
1643
        protected static class InitializationAppender implements ByteCodeAppender {
1644

1645
            /**
1646
             * The values of the enumeration that is being created.
1647
             */
1648
            private final List<String> values;
1649

1650
            /**
1651
             * Creates an appender for an enumerations type initializer.
1652
             *
1653
             * @param values The values of the enumeration that is being created.
1654
             */
1655
            protected InitializationAppender(List<String> values) {
1✔
1656
                this.values = values;
1✔
1657
            }
1✔
1658

1659
            /**
1660
             * {@inheritDoc}
1661
             */
1662
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1663
                TypeDescription instrumentedType = instrumentedMethod.getDeclaringType().asErasure();
1✔
1664
                MethodDescription enumConstructor = instrumentedType.getDeclaredMethods()
1✔
1665
                        .filter(isConstructor().and(takesArguments(String.class, int.class)))
1✔
1666
                        .getOnly();
1✔
1667
                int ordinal = 0;
1✔
1668
                StackManipulation stackManipulation = StackManipulation.Trivial.INSTANCE;
1✔
1669
                List<FieldDescription> enumerationFields = new ArrayList<FieldDescription>(values.size());
1✔
1670
                for (String value : values) {
1✔
1671
                    FieldDescription fieldDescription = instrumentedType.getDeclaredFields().filter(named(value)).getOnly();
1✔
1672
                    stackManipulation = new StackManipulation.Compound(stackManipulation,
1✔
1673
                            TypeCreation.of(instrumentedType),
1✔
1674
                            Duplication.SINGLE,
1675
                            new TextConstant(value),
1676
                            IntegerConstant.forValue(ordinal++),
1✔
1677
                            MethodInvocation.invoke(enumConstructor),
1✔
1678
                            FieldAccess.forField(fieldDescription).write());
1✔
1679
                    enumerationFields.add(fieldDescription);
1✔
1680
                }
1✔
1681
                List<StackManipulation> fieldGetters = new ArrayList<StackManipulation>(values.size());
1✔
1682
                for (FieldDescription fieldDescription : enumerationFields) {
1✔
1683
                    fieldGetters.add(FieldAccess.forField(fieldDescription).read());
1✔
1684
                }
1✔
1685
                stackManipulation = new StackManipulation.Compound(
1✔
1686
                        stackManipulation,
1687
                        ArrayFactory.forType(instrumentedType.asGenericType()).withValues(fieldGetters),
1✔
1688
                        FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(ENUM_VALUES)).getOnly()).write()
1✔
1689
                );
1690
                return new Size(stackManipulation.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1✔
1691
            }
1692
        }
1693
    }
1694

1695
    /**
1696
     * A constructor strategy for implementing a Java record.
1697
     */
1698
    @HashCodeAndEqualsPlugin.Enhance
1✔
1699
    protected enum RecordConstructorStrategy implements ConstructorStrategy, Implementation {
1700

1701
        /**
1702
         * The singleton instance.
1703
         */
1704
        INSTANCE;
1✔
1705

1706
        /**
1707
         * {@inheritDoc}
1708
         */
1709
        public List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType) {
1710
            List<ParameterDescription.Token> tokens = new ArrayList<ParameterDescription.Token>(instrumentedType.getRecordComponents().size());
1✔
1711
            for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1✔
1712
                tokens.add(new ParameterDescription.Token(recordComponent.getType(),
×
1713
                        recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.CONSTRUCTOR)),
×
1714
                        recordComponent.getActualName(),
×
1715
                        ModifierContributor.EMPTY_MASK));
×
1716
            }
×
1717
            return Collections.singletonList(new MethodDescription.Token(MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
1✔
1718
                    Opcodes.ACC_PUBLIC,
1719
                    Collections.<TypeVariableToken>emptyList(),
1✔
1720
                    TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(void.class),
1✔
1721
                    tokens,
1722
                    Collections.<TypeDescription.Generic>emptyList(),
1✔
1723
                    Collections.<AnnotationDescription>emptyList(),
1✔
1724
                    AnnotationValue.UNDEFINED,
1725
                    TypeDescription.Generic.UNDEFINED));
1726
        }
1727

1728
        /**
1729
         * {@inheritDoc}
1730
         */
1731
        public MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry) {
1732
            return methodRegistry.prepend(new LatentMatcher.Resolved<MethodDescription>(isConstructor().and(takesGenericArguments(instrumentedType.getRecordComponents().asTypeList()))),
1✔
1733
                    new MethodRegistry.Handler.ForImplementation(this),
1734
                    MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER,
1735
                    Transformer.ForMethod.NoOp.<MethodDescription>make());
1✔
1736
        }
1737

1738
        /**
1739
         * {@inheritDoc}
1740
         */
1741
        public ByteCodeAppender appender(Target implementationTarget) {
1742
            return new Appender(implementationTarget.getInstrumentedType());
1✔
1743
        }
1744

1745
        /**
1746
         * {@inheritDoc}
1747
         */
1748
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
1749
            for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1✔
1750
                instrumentedType = instrumentedType
×
1751
                        .withField(new FieldDescription.Token(recordComponent.getActualName(),
×
1752
                                Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL,
1753
                                recordComponent.getType(),
×
1754
                                recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.FIELD))))
×
1755
                        .withMethod(new MethodDescription.Token(recordComponent.getActualName(),
×
1756
                                Opcodes.ACC_PUBLIC,
1757
                                Collections.<TypeVariableToken>emptyList(),
×
1758
                                recordComponent.getType(),
×
1759
                                Collections.<ParameterDescription.Token>emptyList(),
×
1760
                                Collections.<TypeDescription.Generic>emptyList(),
×
1761
                                recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.METHOD)),
×
1762
                                AnnotationValue.UNDEFINED,
1763
                                TypeDescription.Generic.UNDEFINED));
1764
            }
×
1765
            return instrumentedType;
1✔
1766
        }
1767

1768
        /**
1769
         * A byte code appender for accessors and the record constructor.
1770
         */
1771
        @HashCodeAndEqualsPlugin.Enhance
1772
        protected static class Appender implements ByteCodeAppender {
1773

1774
            /**
1775
             * The instrumented type.
1776
             */
1777
            private final TypeDescription instrumentedType;
1778

1779
            /**
1780
             * Creates a new byte code appender for accessors and the record constructor.
1781
             *
1782
             * @param instrumentedType The instrumented type.
1783
             */
1784
            protected Appender(TypeDescription instrumentedType) {
1✔
1785
                this.instrumentedType = instrumentedType;
1✔
1786
            }
1✔
1787

1788
            /**
1789
             * {@inheritDoc}
1790
             */
1791
            public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1792
                if (instrumentedMethod.isMethod()) {
×
1793
                    return new Simple(
×
1794
                            MethodVariableAccess.loadThis(),
×
1795
                            FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(instrumentedMethod.getName())).getOnly()).read(),
×
1796
                            MethodReturn.of(instrumentedMethod.getReturnType())
×
1797
                    ).apply(methodVisitor, implementationContext, instrumentedMethod);
×
1798
                } else {
1799
                    List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(instrumentedType.getRecordComponents().size() * 3 + 2);
×
1800
                    stackManipulations.add(MethodVariableAccess.loadThis());
×
1801
                    stackManipulations.add(MethodInvocation.invoke(new MethodDescription.Latent(JavaType.RECORD.getTypeStub(), new MethodDescription.Token(Opcodes.ACC_PUBLIC))));
×
1802
                    int offset = 1;
×
1803
                    for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
×
1804
                        stackManipulations.add(MethodVariableAccess.loadThis());
×
1805
                        stackManipulations.add(MethodVariableAccess.of(recordComponent.getType()).loadFrom(offset));
×
1806
                        stackManipulations.add(FieldAccess.forField(instrumentedType.getDeclaredFields()
×
1807
                                .filter(named(recordComponent.getActualName()))
×
1808
                                .getOnly()).write());
×
1809
                        offset += recordComponent.getType().getStackSize().getSize();
×
1810
                    }
×
1811
                    stackManipulations.add(MethodReturn.VOID);
×
1812
                    return new Simple(stackManipulations).apply(methodVisitor, implementationContext, instrumentedMethod);
×
1813
                }
1814
            }
1815
        }
1816
    }
1817

1818
    /**
1819
     * Implements the object methods of the Java record type.
1820
     */
1821
    @HashCodeAndEqualsPlugin.Enhance
1✔
1822
    protected enum RecordObjectMethod implements Implementation {
1823

1824
        /**
1825
         * The {@code hashCode} method.
1826
         */
1827
        HASH_CODE("hashCode", StackManipulation.Trivial.INSTANCE, int.class),
1✔
1828

1829
        /**
1830
         * The {@code equals} method.
1831
         */
1832
        EQUALS("equals", MethodVariableAccess.REFERENCE.loadFrom(1), boolean.class, Object.class),
1✔
1833

1834
        /**
1835
         * The {@code toString} method.
1836
         */
1837
        TO_STRING("toString", StackManipulation.Trivial.INSTANCE, String.class);
1✔
1838

1839
        /**
1840
         * The method name.
1841
         */
1842
        private final String name;
1843

1844
        /**
1845
         * The stack manipulation to append to the arguments.
1846
         */
1847
        private final StackManipulation stackManipulation;
1848

1849
        /**
1850
         * The return type.
1851
         */
1852
        private final TypeDescription returnType;
1853

1854
        /**
1855
         * The arguments type.
1856
         */
1857
        private final List<? extends TypeDescription> arguments;
1858

1859
        /**
1860
         * Creates a new object method instance for a Java record.
1861
         *
1862
         * @param name              The method name.
1863
         * @param stackManipulation The stack manipulation to append to the arguments.
1864
         * @param returnType        The return type.
1865
         * @param arguments         The arguments type.
1866
         */
1867
        RecordObjectMethod(String name, StackManipulation stackManipulation, Class<?> returnType, Class<?>... arguments) {
1✔
1868
            this.name = name;
1✔
1869
            this.stackManipulation = stackManipulation;
1✔
1870
            this.returnType = TypeDescription.ForLoadedType.of(returnType);
1✔
1871
            this.arguments = new TypeList.ForLoadedTypes(arguments);
1✔
1872
        }
1✔
1873

1874
        /**
1875
         * {@inheritDoc}
1876
         */
1877
        public ByteCodeAppender appender(Target implementationTarget) {
1878
            StringBuilder stringBuilder = new StringBuilder();
1✔
1879
            List<JavaConstant> methodHandles = new ArrayList<JavaConstant>(implementationTarget.getInstrumentedType().getRecordComponents().size());
1✔
1880
            for (RecordComponentDescription.InDefinedShape recordComponent : implementationTarget.getInstrumentedType().getRecordComponents()) {
1✔
1881
                if (stringBuilder.length() > 0) {
×
1882
                    stringBuilder.append(";");
×
1883
                }
1884
                stringBuilder.append(recordComponent.getActualName());
×
1885
                methodHandles.add(JavaConstant.MethodHandle.ofGetter(implementationTarget.getInstrumentedType().getDeclaredFields()
×
1886
                        .filter(named(recordComponent.getActualName()))
×
1887
                        .getOnly()));
×
1888
            }
×
1889
            return new ByteCodeAppender.Simple(MethodVariableAccess.loadThis(),
1✔
1890
                    stackManipulation,
1891
                    MethodInvocation.invoke(new MethodDescription.Latent(JavaType.OBJECT_METHODS.getTypeStub(), new MethodDescription.Token("bootstrap",
1✔
1892
                            Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
1893
                            TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(Object.class),
1✔
1894
                            Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub().asGenericType(),
1✔
1895
                                    TypeDescription.ForLoadedType.of(String.class).asGenericType(),
1✔
1896
                                    JavaType.TYPE_DESCRIPTOR.getTypeStub().asGenericType(),
1✔
1897
                                    TypeDescription.ForLoadedType.of(Class.class).asGenericType(),
1✔
1898
                                    TypeDescription.ForLoadedType.of(String.class).asGenericType(),
1✔
1899
                                    TypeDescription.ArrayProjection.of(JavaType.METHOD_HANDLE.getTypeStub()).asGenericType())))).dynamic(name,
1✔
1900
                            returnType,
1901
                            CompoundList.of(implementationTarget.getInstrumentedType(), arguments),
1✔
1902
                            CompoundList.of(Arrays.asList(JavaConstant.Simple.of(implementationTarget.getInstrumentedType()), JavaConstant.Simple.ofLoaded(stringBuilder.toString())), methodHandles)),
1✔
1903
                    MethodReturn.of(returnType));
1✔
1904
        }
1905

1906
        /**
1907
         * {@inheritDoc}
1908
         */
1909
        public InstrumentedType prepare(InstrumentedType instrumentedType) {
1910
            return instrumentedType;
1✔
1911
        }
1912
    }
1913
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc