1 /*
2 * Copyright 2014 - 2020 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.HashCodeAndEqualsPlugin;
19 import net.bytebuddy.description.annotation.AnnotationDescription;
20 import net.bytebuddy.description.annotation.AnnotationValue;
21 import net.bytebuddy.description.field.FieldDescription;
22 import net.bytebuddy.description.method.MethodDescription;
23 import net.bytebuddy.description.method.ParameterDescription;
24 import net.bytebuddy.description.modifier.*;
25 import net.bytebuddy.description.type.*;
26 import net.bytebuddy.dynamic.*;
27 import net.bytebuddy.dynamic.scaffold.*;
28 import net.bytebuddy.dynamic.scaffold.inline.DecoratingDynamicTypeBuilder;
29 import net.bytebuddy.dynamic.scaffold.inline.MethodNameTransformer;
30 import net.bytebuddy.dynamic.scaffold.inline.RebaseDynamicTypeBuilder;
31 import net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder;
32 import net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
33 import net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder;
34 import net.bytebuddy.implementation.Implementation;
35 import net.bytebuddy.implementation.MethodCall;
36 import net.bytebuddy.implementation.SuperMethodCall;
37 import net.bytebuddy.implementation.attribute.AnnotationRetention;
38 import net.bytebuddy.implementation.attribute.AnnotationValueFilter;
39 import net.bytebuddy.implementation.attribute.MethodAttributeAppender;
40 import net.bytebuddy.implementation.auxiliary.AuxiliaryType;
41 import net.bytebuddy.implementation.bytecode.ByteCodeAppender;
42 import net.bytebuddy.implementation.bytecode.Duplication;
43 import net.bytebuddy.implementation.bytecode.StackManipulation;
44 import net.bytebuddy.implementation.bytecode.TypeCreation;
45 import net.bytebuddy.implementation.bytecode.assign.Assigner;
46 import net.bytebuddy.implementation.bytecode.assign.TypeCasting;
47 import net.bytebuddy.implementation.bytecode.collection.ArrayFactory;
48 import net.bytebuddy.implementation.bytecode.constant.IntegerConstant;
49 import net.bytebuddy.implementation.bytecode.constant.TextConstant;
50 import net.bytebuddy.implementation.bytecode.member.FieldAccess;
51 import net.bytebuddy.implementation.bytecode.member.MethodInvocation;
52 import net.bytebuddy.implementation.bytecode.member.MethodReturn;
53 import net.bytebuddy.implementation.bytecode.member.MethodVariableAccess;
54 import net.bytebuddy.matcher.ElementMatcher;
55 import net.bytebuddy.matcher.LatentMatcher;
56 import net.bytebuddy.utility.CompoundList;
57 import net.bytebuddy.utility.JavaConstant;
58 import net.bytebuddy.utility.JavaType;
59 import net.bytebuddy.jar.asm.MethodVisitor;
60 import net.bytebuddy.jar.asm.Opcodes;
61
62 import java.lang.annotation.Annotation;
63 import java.lang.annotation.ElementType;
64 import java.lang.reflect.Type;
65 import java.util.*;
66
67 import static net.bytebuddy.matcher.ElementMatchers.*;
68
69 /**
70 * Instances of this class serve as a focus point for configuration of the library's behavior and as an entry point
71 * to any form of code generation using the library. For this purpose, Byte Buddy offers a fluent API which allows
72 * for the step-wise generation of a new Java type. A type is generated either by:
73 * <ul>
74 * <li><b>Subclassing</b> some type: A subclass - as the name suggests - extends another, existing Java type. Virtual
75 * members of the generated type's super types can be overridden. Subclasses can also be interface extensions of one
76 * or several interfaces.</li>
77 * <li><b>Redefining</b> a type: By redefining a type, it is not only possible to override virtual methods of the
78 * redefined type but also to redefine existing methods. This way, it is also possible to change the behavior of
79 * non-virtual methods and constructors of the redefined type.</li>
80 * <li><b>Rebasing</b> a type: Rebasing a type works similar to creating a subclass, i.e. any method being overridden
81 * is still capable of invoking any original code of the rebased type. Any rebased method is however inlined into the
82 * rebased type and any original code is preserved automatically. This way, the type's identity does not change.</li>
83 * </ul>
84 * Byte Buddy's API does not change when a type is rebased, redefined or subclassed. All types are created via the
85 * {@link net.bytebuddy.dynamic.DynamicType.Builder} interface. Byte Buddy's API is expressed by fully immutable
86 * components and is therefore thread-safe. As a consequence, method calls must be chained for all of Byte Buddy's
87 * component, e.g. a method call like the following has no effect:
88 * <pre>
89 * ByteBuddy byteBuddy = new ByteBuddy();
90 * byteBuddy.foo()</pre>
91 * Instead, the following method chain is correct use of the API:
92 * <pre>
93 * ByteBuddy byteBuddy = new ByteBuddy().foo();</pre>
94 * <p>
95 * For the creation of Java agents, Byte Buddy offers a convenience API implemented by the
96 * {@link net.bytebuddy.agent.builder.AgentBuilder}. The API wraps a {@link ByteBuddy} instance and offers agent-specific
97 * configuration opportunities by integrating against the {@link java.lang.instrument.Instrumentation} API.
98 * </p>
99 *
100 * @see net.bytebuddy.agent.builder.AgentBuilder
101 */
102 @HashCodeAndEqualsPlugin.Enhance
103 public class ByteBuddy {
104
105 /**
106 * The default prefix for the default {@link net.bytebuddy.NamingStrategy}.
107 */
108 private static final String BYTE_BUDDY_DEFAULT_PREFIX = "ByteBuddy";
109
110 /**
111 * The default suffix when defining a {@link AuxiliaryType.NamingStrategy}.
112 */
113 private static final String BYTE_BUDDY_DEFAULT_SUFFIX = "auxiliary";
114
115 /**
116 * The class file version to use for types that are not based on an existing class file.
117 */
118 protected final ClassFileVersion classFileVersion;
119
120 /**
121 * The naming strategy to use.
122 */
123 protected final NamingStrategy namingStrategy;
124
125 /**
126 * The naming strategy to use for naming auxiliary types.
127 */
128 protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy;
129
130 /**
131 * The annotation value filter factory to use.
132 */
133 protected final AnnotationValueFilter.Factory annotationValueFilterFactory;
134
135 /**
136 * The annotation retention strategy to use.
137 */
138 protected final AnnotationRetention annotationRetention;
139
140 /**
141 * The implementation context factory to use.
142 */
143 protected final Implementation.Context.Factory implementationContextFactory;
144
145 /**
146 * The method graph compiler to use.
147 */
148 protected final MethodGraph.Compiler methodGraphCompiler;
149
150 /**
151 * The instrumented type factory to use.
152 */
153 protected final InstrumentedType.Factory instrumentedTypeFactory;
154
155 /**
156 * A matcher for identifying methods that should be excluded from instrumentation.
157 */
158 protected final LatentMatcher<? super MethodDescription> ignoredMethods;
159
160 /**
161 * Determines if a type should be explicitly validated.
162 */
163 protected final TypeValidation typeValidation;
164
165 /**
166 * The visibility bridge strategy to apply.
167 */
168 protected final VisibilityBridgeStrategy visibilityBridgeStrategy;
169
170 /**
171 * The class writer strategy to use.
172 */
173 protected final ClassWriterStrategy classWriterStrategy;
174
175 /**
176 * <p>
177 * Creates a new Byte Buddy instance with a default configuration that is suitable for most use cases.
178 * </p>
179 * <p>
180 * When creating this configuration, Byte Buddy attempts to discover the current JVM's version. If this
181 * is not possible, class files are created Java 6-compatible.
182 * </p>
183 *
184 * @see ClassFileVersion#ofThisVm(ClassFileVersion)
185 */
186 public ByteBuddy() {
187 this(ClassFileVersion.ofThisVm(ClassFileVersion.JAVA_V6));
188 }
189
190 /**
191 * Creates a new Byte Buddy instance with a default configuration that is suitable for most use cases.
192 *
193 * @param classFileVersion The class file version to use for types that are not based on an existing class file.
194 */
195 public ByteBuddy(ClassFileVersion classFileVersion) {
196 this(classFileVersion,
197 new NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_PREFIX),
198 new AuxiliaryType.NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_SUFFIX),
199 AnnotationValueFilter.Default.APPEND_DEFAULTS,
200 AnnotationRetention.ENABLED,
201 Implementation.Context.Default.Factory.INSTANCE,
202 MethodGraph.Compiler.DEFAULT,
203 InstrumentedType.Factory.Default.MODIFIABLE,
204 TypeValidation.ENABLED,
205 VisibilityBridgeStrategy.Default.ALWAYS,
206 ClassWriterStrategy.Default.CONSTANT_POOL_RETAINING,
207 new LatentMatcher.Resolved<MethodDescription>(isSynthetic().or(isDefaultFinalizer())));
208 }
209
210 /**
211 * Creates a new Byte Buddy instance.
212 *
213 * @param classFileVersion The class file version to use for types that are not based on an existing class file.
214 * @param namingStrategy The naming strategy to use.
215 * @param auxiliaryTypeNamingStrategy The naming strategy to use for naming auxiliary types.
216 * @param annotationValueFilterFactory The annotation value filter factory to use.
217 * @param annotationRetention The annotation retention strategy to use.
218 * @param implementationContextFactory The implementation context factory to use.
219 * @param methodGraphCompiler The method graph compiler to use.
220 * @param instrumentedTypeFactory The instrumented type factory to use.
221 * @param typeValidation Determines if a type should be explicitly validated.
222 * @param visibilityBridgeStrategy The visibility bridge strategy to apply.
223 * @param classWriterStrategy The class writer strategy to use.
224 * @param ignoredMethods A matcher for identifying methods that should be excluded from instrumentation.
225 */
226 protected ByteBuddy(ClassFileVersion classFileVersion,
227 NamingStrategy namingStrategy,
228 AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy,
229 AnnotationValueFilter.Factory annotationValueFilterFactory,
230 AnnotationRetention annotationRetention,
231 Implementation.Context.Factory implementationContextFactory,
232 MethodGraph.Compiler methodGraphCompiler,
233 InstrumentedType.Factory instrumentedTypeFactory,
234 TypeValidation typeValidation,
235 VisibilityBridgeStrategy visibilityBridgeStrategy,
236 ClassWriterStrategy classWriterStrategy,
237 LatentMatcher<? super MethodDescription> ignoredMethods) {
238 this.classFileVersion = classFileVersion;
239 this.namingStrategy = namingStrategy;
240 this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy;
241 this.annotationValueFilterFactory = annotationValueFilterFactory;
242 this.annotationRetention = annotationRetention;
243 this.implementationContextFactory = implementationContextFactory;
244 this.methodGraphCompiler = methodGraphCompiler;
245 this.instrumentedTypeFactory = instrumentedTypeFactory;
246 this.typeValidation = typeValidation;
247 this.visibilityBridgeStrategy = visibilityBridgeStrategy;
248 this.classWriterStrategy = classWriterStrategy;
249 this.ignoredMethods = ignoredMethods;
250 }
251
252 /**
253 * <p>
254 * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
255 * this interface type is created.
256 * </p>
257 * <p>
258 * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type. Any constructor is implemented
259 * to only invoke its super type constructor of equal signature. Another behavior can be specified by supplying an explicit
260 * {@link ConstructorStrategy} by {@link ByteBuddy#subclass(Class, ConstructorStrategy)}.
261 * </p>
262 * <p>
263 * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
264 * </p>
265 * <p>
266 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
267 * types, a external cache or {@link TypeCache} should be used.
268 * </p>
269 *
270 * @param superType The super class or interface type to extend.
271 * @param <T> A loaded type that the generated class is guaranteed to inherit.
272 * @return A type builder for creating a new class extending the provided class or interface.
273 */
274 @SuppressWarnings("unchecked")
275 public <T> DynamicType.Builder<T> subclass(Class<T> superType) {
276 return (DynamicType.Builder<T>) subclass(TypeDescription.ForLoadedType.of(superType));
277 }
278
279 /**
280 * <p>
281 * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
282 * this interface type is created.
283 * </p>
284 * <p>
285 * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
286 * </p>
287 * <p>
288 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
289 * types, a external cache or {@link TypeCache} should be used.
290 * </p>
291 *
292 * @param superType The super class or interface type to extend.
293 * @param constructorStrategy A constructor strategy that determines the
294 * @param <T> A loaded type that the generated class is guaranteed to inherit.
295 * @return A type builder for creating a new class extending the provided class or interface.
296 */
297 @SuppressWarnings("unchecked")
298 public <T> DynamicType.Builder<T> subclass(Class<T> superType, ConstructorStrategy constructorStrategy) {
299 return (DynamicType.Builder<T>) subclass(TypeDescription.ForLoadedType.of(superType), constructorStrategy);
300 }
301
302 /**
303 * <p>
304 * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
305 * this interface type is created.
306 * </p>
307 * <p>
308 * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type. Any constructor is implemented
309 * to only invoke its super type constructor of equal signature. Another behavior can be specified by supplying an explicit
310 * {@link ConstructorStrategy} by {@link ByteBuddy#subclass(Type, ConstructorStrategy)}.
311 * </p>
312 * <p>
313 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
314 * as raw types if they declare type variables.
315 * </p>
316 * <p>
317 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
318 * types, a external cache or {@link TypeCache} should be used.
319 * </p>
320 *
321 * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
322 * variables that are referenced by the generic type must be declared by the generated subclass before creating
323 * the type.
324 * @return A type builder for creating a new class extending the provided class or interface.
325 */
326 public DynamicType.Builder<?> subclass(Type superType) {
327 return subclass(TypeDefinition.Sort.describe(superType));
328 }
329
330 /**
331 * <p>
332 * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
333 * this interface type is created.
334 * </p>
335 * <p>
336 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
337 * as raw types if they declare type variables.
338 * </p>
339 * <p>
340 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
341 * types, a external cache or {@link TypeCache} should be used.
342 * </p>
343 *
344 * @param superType The super class or interface type to extend. The type must be a raw type or parameterized
345 * type. All type variables that are referenced by the generic type must be declared by the
346 * generated subclass before creating the type.
347 * @param constructorStrategy A constructor strategy that determines the
348 * @return A type builder for creating a new class extending the provided class or interface.
349 */
350 public DynamicType.Builder<?> subclass(Type superType, ConstructorStrategy constructorStrategy) {
351 return subclass(TypeDefinition.Sort.describe(superType), constructorStrategy);
352 }
353
354 /**
355 * <p>
356 * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
357 * this interface type is created.
358 * </p>
359 * <p>
360 * When extending a class, Byte Buddy imitates all visible constructors of the subclassed type and sets them to be {@code public}.
361 * Any constructor is implemented to only invoke its super type constructor of equal signature. Another behavior can be specified by
362 * supplying an explicit {@link ConstructorStrategy} by {@link ByteBuddy#subclass(TypeDefinition, ConstructorStrategy)}.
363 * </p>
364 * <p>
365 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
366 * as raw types if they declare type variables.
367 * </p>
368 * <p>
369 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
370 * types, a external cache or {@link TypeCache} should be used.
371 * </p>
372 *
373 * @param superType The super class or interface type to extend. The type must be a raw type or parameterized type. All type
374 * variables that are referenced by the generic type must be declared by the generated subclass before creating
375 * the type.
376 * @return A type builder for creating a new class extending the provided class or interface.
377 */
378 public DynamicType.Builder<?> subclass(TypeDefinition superType) {
379 return subclass(superType, ConstructorStrategy.Default.IMITATE_SUPER_CLASS_OPENING);
380 }
381
382 /**
383 * <p>
384 * Creates a new builder for subclassing the provided type. If the provided type is an interface, a new class implementing
385 * this interface type is created.
386 * </p>
387 * <p>
388 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
389 * as raw types if they declare type variables.
390 * </p>
391 * <p>
392 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
393 * types, a external cache or {@link TypeCache} should be used.
394 * </p>
395 *
396 * @param superType The super class or interface type to extend. The type must be a raw type or parameterized
397 * type. All type variables that are referenced by the generic type must be declared by the
398 * generated subclass before creating the type.
399 * @param constructorStrategy A constructor strategy that determines the
400 * @return A type builder for creating a new class extending the provided class or interface.
401 */
402 public DynamicType.Builder<?> subclass(TypeDefinition superType, ConstructorStrategy constructorStrategy) {
403 TypeDescription.Generic actualSuperType;
404 TypeList.Generic interfaceTypes;
405 if (superType.isPrimitive() || superType.isArray() || superType.isFinal()) {
406 throw new IllegalArgumentException("Cannot subclass primitive, array or final types: " + superType);
407 } else if (superType.isInterface()) {
408 actualSuperType = TypeDescription.Generic.OBJECT;
409 interfaceTypes = new TypeList.Generic.Explicit(superType);
410 } else {
411 actualSuperType = superType.asGenericType();
412 interfaceTypes = new TypeList.Generic.Empty();
413 }
414 return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(namingStrategy.subclass(superType.asGenericType()),
415 ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.PLAIN).resolve(superType.getModifiers()),
416 actualSuperType).withInterfaces(interfaceTypes),
417 classFileVersion,
418 auxiliaryTypeNamingStrategy,
419 annotationValueFilterFactory,
420 annotationRetention,
421 implementationContextFactory,
422 methodGraphCompiler,
423 typeValidation,
424 visibilityBridgeStrategy,
425 classWriterStrategy,
426 ignoredMethods,
427 constructorStrategy);
428 }
429
430 /**
431 * <p>
432 * Creates a new, plain interface type.
433 * </p>
434 * <p>
435 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
436 * types, a external cache or {@link TypeCache} should be used.
437 * </p>
438 *
439 * @return A type builder that creates a new interface type.
440 */
441 public DynamicType.Builder<?> makeInterface() {
442 return makeInterface(Collections.<TypeDescription>emptyList());
443 }
444
445 /**
446 * <p>
447 * Creates a new interface type that extends the provided interface.
448 * </p>
449 * <p>
450 * <b>Note</b>: This methods implements the supplied types in a generified state if they declare type variables or an owner type.
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 interfaceType An interface type that the generated interface implements.
458 * @param <T> A loaded type that the generated interface is guaranteed to inherit.
459 * @return A type builder that creates a new interface type.
460 */
461 @SuppressWarnings("unchecked")
462 public <T> DynamicType.Builder<T> makeInterface(Class<T> interfaceType) {
463 return (DynamicType.Builder<T>) makeInterface(Collections.<Type>singletonList(interfaceType));
464 }
465
466 /**
467 * <p>
468 * Creates a new interface type that extends the provided interface.
469 * </p>
470 * <p>
471 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
472 * as raw types if they declare type variables or an owner type.
473 * </p>
474 * <p>
475 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
476 * types, a external cache or {@link TypeCache} should be used.
477 * </p>
478 *
479 * @param interfaceType The interface types to implement. The types must be raw or parameterized types. All type
480 * variables that are referenced by a parameterized type must be declared by the generated
481 * subclass before creating the type.
482 * @return A type builder that creates a new interface type.
483 */
484 public DynamicType.Builder<?> makeInterface(Type... interfaceType) {
485 return makeInterface(Arrays.asList(interfaceType));
486 }
487
488 /**
489 * <p>
490 * Creates a new interface type that extends the provided interface.
491 * </p>
492 * <p>
493 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link Class} values are implemented
494 * as raw types if they declare type variables or an owner type.
495 * </p>
496 * <p>
497 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
498 * types, a external cache or {@link TypeCache} should be used.
499 * </p>
500 *
501 * @param interfaceTypes The interface types to implement. The types must be raw or parameterized types. All
502 * type variables that are referenced by a parameterized type must be declared by the
503 * generated subclass before creating the type.
504 * @return A type builder that creates a new interface type.
505 */
506 public DynamicType.Builder<?> makeInterface(List<? extends Type> interfaceTypes) {
507 return makeInterface(new TypeList.Generic.ForLoadedTypes(interfaceTypes));
508 }
509
510 /**
511 * <p>
512 * Creates a new interface type that extends the provided interface.
513 * </p>
514 * <p>
515 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
516 * as raw types if they declare type variables or an owner type.
517 * </p>
518 * <p>
519 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
520 * types, a external cache or {@link TypeCache} should be used.
521 * </p>
522 *
523 * @param interfaceType The interface types to implement. The types must be raw or parameterized types. All
524 * type variables that are referenced by a parameterized type must be declared by the
525 * generated subclass before creating the type.
526 * @return A type builder that creates a new interface type.
527 */
528 public DynamicType.Builder<?> makeInterface(TypeDefinition... interfaceType) {
529 return makeInterface(Arrays.asList(interfaceType));
530 }
531
532 /**
533 * <p>
534 * Creates a new interface type that extends the provided interface.
535 * </p>
536 * <p>
537 * <b>Note</b>: This methods implements the supplied types <i>as is</i>, i.e. any {@link TypeDescription} values are implemented
538 * as raw types if they declare type variables or an owner type.
539 * </p>
540 * <p>
541 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
542 * types, a external cache or {@link TypeCache} should be used.
543 * </p>
544 *
545 * @param interfaceTypes The interface types to implement. The types must be raw or parameterized types. All
546 * type variables that are referenced by a parameterized type must be declared by the
547 * generated subclass before creating the type.
548 * @return A type builder that creates a new interface type.
549 */
550 public DynamicType.Builder<?> makeInterface(Collection<? extends TypeDefinition> interfaceTypes) {
551 return subclass(Object.class, ConstructorStrategy.Default.NO_CONSTRUCTORS).implement(interfaceTypes).modifiers(TypeManifestation.INTERFACE, Visibility.PUBLIC);
552 }
553
554 /**
555 * <p>
556 * Creates a new package definition. Package definitions are defined by classes named {@code package-info}
557 * without any methods or fields but permit annotations. Any field or method definition will cause an
558 * {@link IllegalStateException} to be thrown when the type is created.
559 * </p>
560 * <p>
561 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
562 * types, a external cache or {@link TypeCache} should be used.
563 * </p>
564 *
565 * @param name The fully qualified name of the package.
566 * @return A type builder that creates a {@code package-info} class file.
567 */
568 public DynamicType.Builder<?> makePackage(String name) {
569 return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(name + "." + PackageDescription.PACKAGE_CLASS_NAME,
570 PackageDescription.PACKAGE_MODIFIERS,
571 TypeDescription.Generic.OBJECT),
572 classFileVersion,
573 auxiliaryTypeNamingStrategy,
574 annotationValueFilterFactory,
575 annotationRetention,
576 implementationContextFactory,
577 methodGraphCompiler,
578 typeValidation,
579 visibilityBridgeStrategy,
580 classWriterStrategy,
581 ignoredMethods,
582 ConstructorStrategy.Default.NO_CONSTRUCTORS);
583 }
584
585 /**
586 * Creates a new Java record. This builder automatically defines fields for record members, standard accessors and a record constructor for any
587 * defined record component.
588 *
589 * @return A dynamic type builder that creates a record.
590 */
591 public DynamicType.Builder<?> makeRecord() {
592 TypeDescription.Generic record = InstrumentedType.Default.of(JavaType.RECORD.getTypeStub().getName(), TypeDescription.Generic.OBJECT, Visibility.PUBLIC)
593 .withMethod(new MethodDescription.Token(Opcodes.ACC_PROTECTED))
594 .withMethod(new MethodDescription.Token("hashCode",
595 Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
596 TypeDescription.ForLoadedType.of(int.class).asGenericType()))
597 .withMethod(new MethodDescription.Token("equals",
598 Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
599 TypeDescription.ForLoadedType.of(boolean.class).asGenericType(),
600 Collections.singletonList(TypeDescription.Generic.OBJECT)))
601 .withMethod(new MethodDescription.Token("toString",
602 Opcodes.ACC_PUBLIC | Opcodes.ACC_ABSTRACT,
603 TypeDescription.ForLoadedType.of(String.class).asGenericType()))
604 .asGenericType();
605 return new SubclassDynamicTypeBuilder<Object>(instrumentedTypeFactory.subclass(namingStrategy.subclass(record), Opcodes.ACC_PUBLIC | Opcodes.ACC_FINAL, record).withRecord(true),
606 classFileVersion,
607 auxiliaryTypeNamingStrategy,
608 annotationValueFilterFactory,
609 annotationRetention,
610 implementationContextFactory,
611 methodGraphCompiler,
612 typeValidation,
613 visibilityBridgeStrategy,
614 classWriterStrategy,
615 ignoredMethods,
616 RecordConstructorStrategy.INSTANCE)
617 .method(isHashCode()).intercept(RecordObjectMethod.HASH_CODE)
618 .method(isEquals()).intercept(RecordObjectMethod.EQUALS)
619 .method(isToString()).intercept(RecordObjectMethod.TO_STRING);
620 }
621
622 /**
623 * <p>
624 * Creates a new {@link Annotation} type. Annotation properties are implemented as non-static, public methods with the
625 * property type being defined as the return type.
626 * </p>
627 * <p>
628 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
629 * types, a external cache or {@link TypeCache} should be used.
630 * </p>
631 *
632 * @return A type builder that creates a new {@link Annotation} type.
633 */
634 public DynamicType.Builder<? extends Annotation> makeAnnotation() {
635 return new SubclassDynamicTypeBuilder<Annotation>(instrumentedTypeFactory.subclass(namingStrategy.subclass(TypeDescription.Generic.ANNOTATION),
636 ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.ANNOTATION).resolve(),
637 TypeDescription.Generic.OBJECT).withInterfaces(new TypeList.Generic.Explicit(TypeDescription.Generic.ANNOTATION)),
638 classFileVersion,
639 auxiliaryTypeNamingStrategy,
640 annotationValueFilterFactory,
641 annotationRetention,
642 implementationContextFactory,
643 methodGraphCompiler,
644 typeValidation,
645 visibilityBridgeStrategy,
646 classWriterStrategy,
647 ignoredMethods,
648 ConstructorStrategy.Default.NO_CONSTRUCTORS);
649 }
650
651 /**
652 * <p>
653 * Creates a new {@link Enum} 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 value The names of the type's enumeration constants
661 * @return A type builder for creating an enumeration type.
662 */
663 public DynamicType.Builder<? extends Enum<?>> makeEnumeration(String... value) {
664 return makeEnumeration(Arrays.asList(value));
665 }
666
667 /**
668 * <p>
669 * Creates a new {@link Enum} type.
670 * </p>
671 * <p>
672 * <b>Note</b>: Byte Buddy does not cache previous subclasses but will attempt the generation of a new subclass. For caching
673 * types, a external cache or {@link TypeCache} should be used.
674 * </p>
675 *
676 * @param values The names of the type's enumeration constants
677 * @return A type builder for creating an enumeration type.
678 */
679 public DynamicType.Builder<? extends Enum<?>> makeEnumeration(Collection<? extends String> values) {
680 if (values.isEmpty()) {
681 throw new IllegalArgumentException("Require at least one enumeration constant");
682 }
683 TypeDescription.Generic enumType = TypeDescription.Generic.Builder.parameterizedType(Enum.class, TargetType.class).build();
684 return new SubclassDynamicTypeBuilder<Enum<?>>(instrumentedTypeFactory.subclass(namingStrategy.subclass(enumType),
685 ModifierContributor.Resolver.of(Visibility.PUBLIC, TypeManifestation.FINAL, EnumerationState.ENUMERATION).resolve(),
686 enumType),
687 classFileVersion,
688 auxiliaryTypeNamingStrategy,
689 annotationValueFilterFactory,
690 annotationRetention,
691 implementationContextFactory,
692 methodGraphCompiler,
693 typeValidation,
694 visibilityBridgeStrategy,
695 classWriterStrategy,
696 ignoredMethods,
697 ConstructorStrategy.Default.NO_CONSTRUCTORS)
698 .defineConstructor(Visibility.PRIVATE).withParameters(String.class, int.class)
699 .intercept(SuperMethodCall.INSTANCE)
700 .defineMethod(EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME,
701 TargetType.class,
702 Visibility.PUBLIC, Ownership.STATIC).withParameters(String.class)
703 .intercept(MethodCall.invoke(enumType.getDeclaredMethods()
704 .filter(named(EnumerationImplementation.ENUM_VALUE_OF_METHOD_NAME).and(takesArguments(Class.class, String.class))).getOnly())
705 .withOwnType().withArgument(0)
706 .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC))
707 .defineMethod(EnumerationImplementation.ENUM_VALUES_METHOD_NAME,
708 TargetType[].class,
709 Visibility.PUBLIC, Ownership.STATIC)
710 .intercept(new EnumerationImplementation(new ArrayList<String>(values)));
711 }
712
713 /**
714 * <p>
715 * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
716 * by the new implementation.
717 * </p>
718 * <p>
719 * The class file of the redefined type is located by querying the redefined type's class loader by name. For specifying an
720 * alternative {@link ClassFileLocator}, use {@link ByteBuddy#redefine(Class, ClassFileLocator)}.
721 * </p>
722 * <p>
723 * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
724 * 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.
725 * 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
726 * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
727 * where the class initializer is retained <i>as is</i>.
728 * </p>
729 *
730 * @param type The type that is being redefined.
731 * @param <T> The loaded type of the redefined type.
732 * @return A type builder for redefining the provided type.
733 */
734 public <T> DynamicType.Builder<T> redefine(Class<T> type) {
735 return redefine(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
736 }
737
738 /**
739 * <p>
740 * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
741 * by the new implementation.
742 * </p>
743 * <p>
744 * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
745 * 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.
746 * 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
747 * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
748 * where the class initializer is retained <i>as is</i>.
749 * </p>
750 *
751 * @param type The type that is being redefined.
752 * @param classFileLocator The class file locator that is queried for the redefined type's class file.
753 * @param <T> The loaded type of the redefined type.
754 * @return A type builder for redefining the provided type.
755 */
756 public <T> DynamicType.Builder<T> redefine(Class<T> type, ClassFileLocator classFileLocator) {
757 return redefine(TypeDescription.ForLoadedType.of(type), classFileLocator);
758 }
759
760 /**
761 * <p>
762 * Redefines the given type where any intercepted method that is declared by the redefined type is fully replaced
763 * by the new implementation.
764 * </p>
765 * <p>
766 * <b>Note</b>: When a user redefines a class with the purpose of reloading this class using a {@link net.bytebuddy.dynamic.loading.ClassReloadingStrategy},
767 * 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.
768 * 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
769 * {@link ByteBuddy#with(Implementation.Context.Factory)} to use a {@link net.bytebuddy.implementation.Implementation.Context.Disabled.Factory}
770 * where the class initializer is retained <i>as is</i>.
771 * </p>
772 *
773 * @param type The type that is being redefined.
774 * @param classFileLocator The class file locator that is queried for the redefined type's class file.
775 * @param <T> The loaded type of the redefined type.
776 * @return A type builder for redefining the provided type.
777 */
778 public <T> DynamicType.Builder<T> redefine(TypeDescription type, ClassFileLocator classFileLocator) {
779 if (type.isArray() || type.isPrimitive()) {
780 throw new IllegalArgumentException("Cannot redefine array or primitive type: " + type);
781 }
782 return new RedefinitionDynamicTypeBuilder<T>(instrumentedTypeFactory.represent(type),
783 classFileVersion,
784 auxiliaryTypeNamingStrategy,
785 annotationValueFilterFactory,
786 annotationRetention,
787 implementationContextFactory,
788 methodGraphCompiler,
789 typeValidation,
790 visibilityBridgeStrategy,
791 classWriterStrategy,
792 ignoredMethods,
793 type,
794 classFileLocator);
795 }
796
797 /**
798 * <p>
799 * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
800 * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
801 * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
802 * </p>
803 * <p>
804 * The class file of the rebased type is located by querying the rebased type's class loader by name. For specifying an
805 * alternative {@link ClassFileLocator}, use {@link ByteBuddy#redefine(Class, ClassFileLocator)}.
806 * </p>
807 *
808 * @param type The type that is being rebased.
809 * @param <T> The loaded type of the rebased type.
810 * @return A type builder for rebasing the provided type.
811 */
812 public <T> DynamicType.Builder<T> rebase(Class<T> type) {
813 return rebase(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
814 }
815
816 /**
817 * <p>
818 * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
819 * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
820 * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
821 * </p>
822 * <p>
823 * When a method is rebased, the original method is copied into a new method with a different name. These names are
824 * generated automatically by Byte Buddy unless a {@link MethodNameTransformer} is specified explicitly.
825 * Use {@link ByteBuddy#rebase(Class, ClassFileLocator, MethodNameTransformer)} for doing so.
826 * </p>
827 *
828 * @param type The type that is being rebased.
829 * @param classFileLocator The class file locator that is queried for the rebased type's class file.
830 * @param <T> The loaded type of the rebased type.
831 * @return A type builder for rebasing the provided type.
832 */
833 public <T> DynamicType.Builder<T> rebase(Class<T> type, ClassFileLocator classFileLocator) {
834 return rebase(TypeDescription.ForLoadedType.of(type), classFileLocator);
835 }
836
837 /**
838 * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
839 * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
840 * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
841 *
842 * @param type The type that is being rebased.
843 * @param classFileLocator The class file locator that is queried for the rebased type's class file.
844 * @param methodNameTransformer The method name transformer for renaming a method that is rebased.
845 * @param <T> The loaded type of the rebased type.
846 * @return A type builder for rebasing the provided type.
847 */
848 public <T> DynamicType.Builder<T> rebase(Class<T> type, ClassFileLocator classFileLocator, MethodNameTransformer methodNameTransformer) {
849 return rebase(TypeDescription.ForLoadedType.of(type), classFileLocator, methodNameTransformer);
850 }
851
852 /**
853 * <p>
854 * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
855 * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
856 * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
857 * </p>
858 * <p>
859 * When a method is rebased, the original method is copied into a new method with a different name. These names are
860 * generated automatically by Byte Buddy unless a {@link MethodNameTransformer} is specified explicitly.
861 * Use {@link ByteBuddy#rebase(TypeDescription, ClassFileLocator, MethodNameTransformer)} for doing so.
862 * </p>
863 *
864 * @param type The type that is being rebased.
865 * @param classFileLocator The class file locator that is queried for the rebased type's class file.
866 * @param <T> The loaded type of the rebased type.
867 * @return A type builder for rebasing the provided type.
868 */
869 public <T> DynamicType.Builder<T> rebase(TypeDescription type, ClassFileLocator classFileLocator) {
870 return rebase(type, classFileLocator, MethodNameTransformer.Suffixing.withRandomSuffix());
871 }
872
873 /**
874 * Rebases the given type where any intercepted method that is declared by the redefined type is preserved within the
875 * rebased type's class such that the class's original can be invoked from the new method implementations. Rebasing a
876 * type can be seen similarly to creating a subclass where the subclass is later merged with the original class file.
877 *
878 * @param type The type that is being rebased.
879 * @param classFileLocator The class file locator that is queried for the rebased type's class file.
880 * @param methodNameTransformer The method name transformer for renaming a method that is rebased.
881 * @param <T> The loaded type of the rebased type.
882 * @return A type builder for rebasing the provided type.
883 */
884 public <T> DynamicType.Builder<T> rebase(TypeDescription type, ClassFileLocator classFileLocator, MethodNameTransformer methodNameTransformer) {
885 if (type.isArray() || type.isPrimitive()) {
886 throw new IllegalArgumentException("Cannot rebase array or primitive type: " + type);
887 }
888 return new RebaseDynamicTypeBuilder<T>(instrumentedTypeFactory.represent(type),
889 classFileVersion,
890 auxiliaryTypeNamingStrategy,
891 annotationValueFilterFactory,
892 annotationRetention,
893 implementationContextFactory,
894 methodGraphCompiler,
895 typeValidation,
896 visibilityBridgeStrategy,
897 classWriterStrategy,
898 ignoredMethods,
899 type,
900 classFileLocator,
901 methodNameTransformer);
902 }
903
904 /**
905 * Rebases a package. This offers an opportunity to add annotations to the package definition. Packages are defined
906 * by classes named {@code package-info} without any methods or fields but permit annotations. Any field or method
907 * definition will cause an {@link IllegalStateException} to be thrown when the type is created.
908 *
909 * @param aPackage The package that is being rebased.
910 * @param classFileLocator The class file locator to use for locating the package's class file.
911 * @return A type builder for rebasing the given package.
912 */
913 public DynamicType.Builder<?> rebase(Package aPackage, ClassFileLocator classFileLocator) {
914 return rebase(new PackageDescription.ForLoadedPackage(aPackage), classFileLocator);
915 }
916
917 /**
918 * Rebases a package. This offers an opportunity to add annotations to the package definition. Packages are defined
919 * by classes named {@code package-info} without any methods or fields but permit annotations. Any field or method
920 * definition will cause an {@link IllegalStateException} to be thrown when the type is created.
921 *
922 * @param aPackage The package that is being rebased.
923 * @param classFileLocator The class file locator to use for locating the package's class file.
924 * @return A type builder for rebasing the given package.
925 */
926 public DynamicType.Builder<?> rebase(PackageDescription aPackage, ClassFileLocator classFileLocator) {
927 return rebase(new TypeDescription.ForPackageDescription(aPackage), classFileLocator);
928 }
929
930 /**
931 * <p>
932 * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
933 * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
934 * when implementing a Java agent that only applies ASM-based code changes.
935 * </p>
936 * <p>
937 * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
938 * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
939 * {@link Implementation.Context.Factory} that does not attempt any type transformation.
940 * </p>
941 *
942 * @param type The type to decorate.
943 * @param <T> The loaded type of the decorated type.
944 * @return A type builder for decorating the provided type.
945 */
946 public <T> DynamicType.Builder<T> decorate(Class<T> type) {
947 return decorate(type, ClassFileLocator.ForClassLoader.of(type.getClassLoader()));
948 }
949
950 /**
951 * <p>
952 * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
953 * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
954 * when implementing a Java agent that only applies ASM-based code changes.
955 * </p>
956 * <p>
957 * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
958 * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
959 * {@link Implementation.Context.Factory} that does not attempt any type transformation.
960 * </p>
961 *
962 * @param type The type to decorate.
963 * @param classFileLocator The class file locator to use.
964 * @param <T> The loaded type of the decorated type.
965 * @return A type builder for decorating the provided type.
966 */
967 public <T> DynamicType.Builder<T> decorate(Class<T> type, ClassFileLocator classFileLocator) {
968 return decorate(TypeDescription.ForLoadedType.of(type), classFileLocator);
969 }
970
971 /**
972 * <p>
973 * Decorates a type with {@link net.bytebuddy.asm.AsmVisitorWrapper} and allows adding attributes and annotations. A decoration does
974 * not allow for any standard transformations but can be used as a performance optimization compared to a redefinition, especially
975 * when implementing a Java agent that only applies ASM-based code changes.
976 * </p>
977 * <p>
978 * <b>Important</b>: Only use this mode to improve performance in a narrowly defined transformation. Using other features as those mentioned
979 * might result in an unexpected outcome of the transformation or error. Using decoration also requires the configuration of an
980 * {@link Implementation.Context.Factory} that does not attempt any type transformation.
981 * </p>
982 *
983 * @param type The type to decorate.
984 * @param classFileLocator The class file locator to use.
985 * @param <T> The loaded type of the decorated type.
986 * @return A type builder for decorating the provided type.
987 */
988 public <T> DynamicType.Builder<T> decorate(TypeDescription type, ClassFileLocator classFileLocator) {
989 if (type.isArray() || type.isPrimitive()) {
990 throw new IllegalArgumentException("Cannot decorate array or primitive type: " + type);
991 }
992 return new DecoratingDynamicTypeBuilder<T>(type,
993 classFileVersion,
994 auxiliaryTypeNamingStrategy,
995 annotationValueFilterFactory,
996 annotationRetention,
997 implementationContextFactory,
998 methodGraphCompiler,
999 typeValidation,
1000 classWriterStrategy,
1001 ignoredMethods,
1002 classFileLocator);
1003 }
1004
1005 /**
1006 * Creates a new configuration where all class files that are not based on an existing class file are created
1007 * using the supplied class file version. When creating a Byte Buddy instance by {@link ByteBuddy#ByteBuddy()}, the class
1008 * file version is detected automatically. If the class file version is known before creating a Byte Buddy instance, the
1009 * {@link ByteBuddy#ByteBuddy(ClassFileVersion)} constructor should be used.
1010 *
1011 * @param classFileVersion The class file version to use for types that are not based on an existing class file.
1012 * @return A new Byte Buddy instance that uses the supplied class file version.
1013 */
1014 public ByteBuddy with(ClassFileVersion classFileVersion) {
1015 return new ByteBuddy(classFileVersion,
1016 namingStrategy,
1017 auxiliaryTypeNamingStrategy,
1018 annotationValueFilterFactory,
1019 annotationRetention,
1020 implementationContextFactory,
1021 methodGraphCompiler,
1022 instrumentedTypeFactory,
1023 typeValidation,
1024 visibilityBridgeStrategy,
1025 classWriterStrategy,
1026 ignoredMethods);
1027 }
1028
1029 /**
1030 * Creates a new configuration where new types are named by applying the given naming strategy. By default, Byte Buddy
1031 * simply retains the name of rebased and redefined types but adds a random suffix to the name of created subclasses or
1032 * -interfaces. If a type is defined within the {@code java.*} namespace, Byte Buddy also adds a suffix to the generated
1033 * class because this namespace is only available for the bootstrap class loader.
1034 *
1035 * @param namingStrategy The naming strategy to apply when creating a new dynamic type.
1036 * @return A new Byte Buddy instance that uses the supplied naming strategy.
1037 */
1038 public ByteBuddy with(NamingStrategy namingStrategy) {
1039 return new ByteBuddy(classFileVersion,
1040 namingStrategy,
1041 auxiliaryTypeNamingStrategy,
1042 annotationValueFilterFactory,
1043 annotationRetention,
1044 implementationContextFactory,
1045 methodGraphCompiler,
1046 instrumentedTypeFactory,
1047 typeValidation,
1048 visibilityBridgeStrategy,
1049 classWriterStrategy,
1050 ignoredMethods);
1051 }
1052
1053 /**
1054 * Creates a new configuration where auxiliary types are named by applying the given naming strategy. Auxiliary types
1055 * are helper types that might be required for implementing certain {@link Implementation}s. By default, Byte Buddy
1056 * adds a random suffix to the instrumented type's name when naming its auxiliary types.
1057 *
1058 * @param auxiliaryTypeNamingStrategy The naming strategy to apply when creating a new auxiliary type.
1059 * @return A new Byte Buddy instance that uses the supplied naming strategy for auxiliary types.
1060 */
1061 public ByteBuddy with(AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy) {
1062 return new ByteBuddy(classFileVersion,
1063 namingStrategy,
1064 auxiliaryTypeNamingStrategy,
1065 annotationValueFilterFactory,
1066 annotationRetention,
1067 implementationContextFactory,
1068 methodGraphCompiler,
1069 instrumentedTypeFactory,
1070 typeValidation,
1071 visibilityBridgeStrategy,
1072 classWriterStrategy,
1073 ignoredMethods);
1074 }
1075
1076 /**
1077 * Creates a new configuration where annotation values are written according to the given filter factory. Using
1078 * a filter factory, it is for example possible not to include certain values into a class file such that the
1079 * runtime returns an annotation type's default value. By default, Byte Buddy includes all values into a class file,
1080 * also such values for which a default value exists.
1081 *
1082 * @param annotationValueFilterFactory The annotation value filter factory to use.
1083 * @return A new Byte Buddy instance that uses the supplied annotation value filter factory.
1084 */
1085 public ByteBuddy with(AnnotationValueFilter.Factory annotationValueFilterFactory) {
1086 return new ByteBuddy(classFileVersion,
1087 namingStrategy,
1088 auxiliaryTypeNamingStrategy,
1089 annotationValueFilterFactory,
1090 annotationRetention,
1091 implementationContextFactory,
1092 methodGraphCompiler,
1093 instrumentedTypeFactory,
1094 typeValidation,
1095 visibilityBridgeStrategy,
1096 classWriterStrategy,
1097 ignoredMethods);
1098 }
1099
1100 /**
1101 * <p>
1102 * Creates a new configuration where annotations that are found in an existing class file are or are not preserved
1103 * in the format they are discovered, i.e. rewritten in the format they were already present in the class file.
1104 * By default, Byte Buddy retains annotations when a class is rebased or redefined.
1105 * </p>
1106 * <p>
1107 * <b>Warning</b>: Retaining annotations can cause problems when annotations of a field or method are added based
1108 * on the annotations of a matched method. Doing so, Byte Buddy might write the annotations of the field or method
1109 * explicitly to a class file while simultaneously retaining the existing annotation what results in duplicates.
1110 * When matching fields or methods while adding annotations, disabling annotation retention might be required.
1111 * </p>
1112 *
1113 * @param annotationRetention The annotation retention strategy to use.
1114 * @return A new Byte Buddy instance that uses the supplied annotation retention strategy.
1115 */
1116 public ByteBuddy with(AnnotationRetention annotationRetention) {
1117 return new ByteBuddy(classFileVersion,
1118 namingStrategy,
1119 auxiliaryTypeNamingStrategy,
1120 annotationValueFilterFactory,
1121 annotationRetention,
1122 implementationContextFactory,
1123 methodGraphCompiler,
1124 instrumentedTypeFactory,
1125 typeValidation,
1126 visibilityBridgeStrategy,
1127 classWriterStrategy,
1128 ignoredMethods);
1129 }
1130
1131 /**
1132 * Creates a new configuration where the {@link net.bytebuddy.implementation.Implementation.Context} of any created
1133 * type is a product of the given implementation context factory. An implementation context might imply unwanted
1134 * side-effects, for example, the creation of an additional synthetic methods in order to support specific features
1135 * for realizing an {@link Implementation}. By default, Byte Buddy supplies a factory that enables all features. When
1136 * redefining a loaded class, it is however required by the JVM that no additional members are added such that a
1137 * {@link net.bytebuddy.implementation.Implementation.Context.Disabled} factory might be more appropriate.
1138 *
1139 * @param implementationContextFactory The implementation context factory to use for defining an instrumented type.
1140 * @return A new Byte Buddy instance that uses the supplied implementation context factory.
1141 */
1142 public ByteBuddy with(Implementation.Context.Factory implementationContextFactory) {
1143 return new ByteBuddy(classFileVersion,
1144 namingStrategy,
1145 auxiliaryTypeNamingStrategy,
1146 annotationValueFilterFactory,
1147 annotationRetention,
1148 implementationContextFactory,
1149 methodGraphCompiler,
1150 instrumentedTypeFactory,
1151 typeValidation,
1152 visibilityBridgeStrategy,
1153 classWriterStrategy,
1154 ignoredMethods);
1155 }
1156
1157 /**
1158 * Creates a new configuration where the {@link MethodGraph.Compiler} is used for creating a {@link MethodGraph}
1159 * of the instrumented type. A method graph is a representation of a type's virtual methods, including all information
1160 * on bridge methods that are inserted by the Java compiler. Creating a method graph is a rather expensive operation
1161 * and more efficient strategies might exist for certain types or ava types that are created by alternative JVM
1162 * languages. By default, a general purpose method graph compiler is used that uses the information that is exposed
1163 * by the generic type information that is embedded in any class file.
1164 *
1165 * @param methodGraphCompiler The method graph compiler to use for analyzing the instrumented type.
1166 * @return A new Byte Buddy instance that uses the supplied method graph compiler.
1167 */
1168 public ByteBuddy with(MethodGraph.Compiler methodGraphCompiler) {
1169 return new ByteBuddy(classFileVersion,
1170 namingStrategy,
1171 auxiliaryTypeNamingStrategy,
1172 annotationValueFilterFactory,
1173 annotationRetention,
1174 implementationContextFactory,
1175 methodGraphCompiler,
1176 instrumentedTypeFactory,
1177 typeValidation,
1178 visibilityBridgeStrategy,
1179 classWriterStrategy,
1180 ignoredMethods);
1181 }
1182
1183 /**
1184 * Configures Byte Buddy to use the specified factory for creating {@link InstrumentedType}s. Doing so, more efficient
1185 * representations can be chosen when only certain operations are required. By default, all operations are supported.
1186 *
1187 * @param instrumentedTypeFactory The factory to use when creating instrumented types.
1188 * @return A new Byte Buddy instance that uses the supplied factory for creating instrumented types.
1189 */
1190 public ByteBuddy with(InstrumentedType.Factory instrumentedTypeFactory) {
1191 return new ByteBuddy(classFileVersion,
1192 namingStrategy,
1193 auxiliaryTypeNamingStrategy,
1194 annotationValueFilterFactory,
1195 annotationRetention,
1196 implementationContextFactory,
1197 methodGraphCompiler,
1198 instrumentedTypeFactory,
1199 typeValidation,
1200 visibilityBridgeStrategy,
1201 classWriterStrategy,
1202 ignoredMethods);
1203 }
1204
1205 /**
1206 * Creates a new configuration that applies the supplied type validation. By default, explicitly type validation is applied
1207 * by Byte Buddy but it might be disabled for performance reason or for voluntarily creating illegal types. The Java virtual
1208 * machine applies its own type validation where some {@link Error} is thrown if a type is invalid, while Byte Buddy throws
1209 * some {@link RuntimeException}.
1210 *
1211 * @param typeValidation The type validation to apply during type creation.
1212 * @return A new Byte Buddy instance that applies the supplied type validation.
1213 */
1214 public ByteBuddy with(TypeValidation typeValidation) {
1215 return new ByteBuddy(classFileVersion,
1216 namingStrategy,
1217 auxiliaryTypeNamingStrategy,
1218 annotationValueFilterFactory,
1219 annotationRetention,
1220 implementationContextFactory,
1221 methodGraphCompiler,
1222 instrumentedTypeFactory,
1223 typeValidation,
1224 visibilityBridgeStrategy,
1225 classWriterStrategy,
1226 ignoredMethods);
1227 }
1228
1229 /**
1230 * Creates a new configuration that applies the supplied visibility bridge strategy. By default, visibility bridges
1231 * are create for all methods for which a visibility bridge is normally necessary.
1232 *
1233 * @param visibilityBridgeStrategy The visibility bridge strategy to apply.
1234 * @return A new Byte Buddy instance that applies the supplied visibility bridge strategy.
1235 */
1236 public ByteBuddy with(VisibilityBridgeStrategy visibilityBridgeStrategy) {
1237 return new ByteBuddy(classFileVersion,
1238 namingStrategy,
1239 auxiliaryTypeNamingStrategy,
1240 annotationValueFilterFactory,
1241 annotationRetention,
1242 implementationContextFactory,
1243 methodGraphCompiler,
1244 instrumentedTypeFactory,
1245 typeValidation,
1246 visibilityBridgeStrategy,
1247 classWriterStrategy,
1248 ignoredMethods);
1249 }
1250
1251 /**
1252 * Creates a new configuration that applies the supplied class writer strategy. By default, the constant pool of redefined and retransformed
1253 * classes is retained as most changes are additive and this retention improves performance.
1254 *
1255 * @param classWriterStrategy The class writer strategy to apply during type creation.
1256 * @return A new Byte Buddy instance that applies the supplied class writer strategy.
1257 */
1258 public ByteBuddy with(ClassWriterStrategy classWriterStrategy) {
1259 return new ByteBuddy(classFileVersion,
1260 namingStrategy,
1261 auxiliaryTypeNamingStrategy,
1262 annotationValueFilterFactory,
1263 annotationRetention,
1264 implementationContextFactory,
1265 methodGraphCompiler,
1266 instrumentedTypeFactory,
1267 typeValidation,
1268 visibilityBridgeStrategy,
1269 classWriterStrategy,
1270 ignoredMethods);
1271 }
1272
1273 /**
1274 * Creates a new configuration where any {@link MethodDescription} that matches the provided method matcher is excluded
1275 * from instrumentation. Any previous matcher for ignored methods is replaced. By default, Byte Buddy ignores any
1276 * synthetic method (bridge methods are handled automatically) and the {@link Object#finalize()} method.
1277 *
1278 * @param ignoredMethods A matcher for identifying methods to be excluded from instrumentation.
1279 * @return A new Byte Buddy instance that excludes any method from instrumentation if it is matched by the supplied matcher.
1280 */
1281 public ByteBuddy ignore(ElementMatcher<? super MethodDescription> ignoredMethods) {
1282 return ignore(new LatentMatcher.Resolved<MethodDescription>(ignoredMethods));
1283 }
1284
1285 /**
1286 * <p>
1287 * Creates a new configuration where any {@link MethodDescription} that matches the provided method matcher is excluded
1288 * from instrumentation. Any previous matcher for ignored methods is replaced. By default, Byte Buddy ignores any
1289 * synthetic method (bridge methods are handled automatically) and the {@link Object#finalize()} method. Using a latent
1290 * matcher gives opportunity to resolve an {@link ElementMatcher} based on the instrumented type before applying the matcher.
1291 * </p>
1292 *
1293 * @param ignoredMethods A matcher for identifying methods to be excluded from instrumentation.
1294 * @return A new Byte Buddy instance that excludes any method from instrumentation if it is matched by the supplied matcher.
1295 */
1296 public ByteBuddy ignore(LatentMatcher<? super MethodDescription> ignoredMethods) {
1297 return new ByteBuddy(classFileVersion,
1298 namingStrategy,
1299 auxiliaryTypeNamingStrategy,
1300 annotationValueFilterFactory,
1301 annotationRetention,
1302 implementationContextFactory,
1303 methodGraphCompiler,
1304 instrumentedTypeFactory,
1305 typeValidation,
1306 visibilityBridgeStrategy,
1307 classWriterStrategy,
1308 ignoredMethods);
1309 }
1310
1311 /**
1312 * An implementation fo the {@code values} method of an enumeration type.
1313 */
1314 @HashCodeAndEqualsPlugin.Enhance
1315 protected static class EnumerationImplementation implements Implementation {
1316
1317 /**
1318 * The name of the {@link java.lang.Object#clone()} method.
1319 */
1320 protected static final String CLONE_METHOD_NAME = "clone";
1321
1322 /**
1323 * The name of the {@code valueOf} method that is defined for any enumeration.
1324 */
1325 protected static final String ENUM_VALUE_OF_METHOD_NAME = "valueOf";
1326
1327 /**
1328 * The name of the {@code values} method that is defined for any enumeration.
1329 */
1330 protected static final String ENUM_VALUES_METHOD_NAME = "values";
1331
1332 /**
1333 * The field modifiers to use for any field that is added to an enumeration.
1334 */
1335 private static final int ENUM_FIELD_MODIFIERS = Opcodes.ACC_FINAL | Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC;
1336
1337 /**
1338 * The name of the field containing an array of all enumeration values.
1339 */
1340 private static final String ENUM_VALUES = "$VALUES";
1341
1342 /**
1343 * The names of the enumerations to define for the enumeration.
1344 */
1345 private final List<String> values;
1346
1347 /**
1348 * Creates a new implementation of an enumeration type.
1349 *
1350 * @param values The values of the enumeration.
1351 */
1352 protected EnumerationImplementation(List<String> values) {
1353 this.values = values;
1354 }
1355
1356 /**
1357 * {@inheritDoc}
1358 */
1359 public InstrumentedType prepare(InstrumentedType instrumentedType) {
1360 for (String value : values) {
1361 instrumentedType = instrumentedType.withField(new FieldDescription.Token(value,
1362 ENUM_FIELD_MODIFIERS | Opcodes.ACC_ENUM,
1363 TargetType.DESCRIPTION.asGenericType()));
1364 }
1365 return instrumentedType
1366 .withField(new FieldDescription.Token(ENUM_VALUES,
1367 ENUM_FIELD_MODIFIERS | Opcodes.ACC_SYNTHETIC,
1368 TypeDescription.ArrayProjection.of(TargetType.DESCRIPTION).asGenericType()))
1369 .withInitializer(new InitializationAppender(values));
1370 }
1371
1372 /**
1373 * {@inheritDoc}
1374 */
1375 public ByteCodeAppender appender(Target implementationTarget) {
1376 return new ValuesMethodAppender(implementationTarget.getInstrumentedType());
1377 }
1378
1379 /**
1380 * A byte code appender for the {@code values} method of any enumeration type.
1381 */
1382 @HashCodeAndEqualsPlugin.Enhance
1383 protected static class ValuesMethodAppender implements ByteCodeAppender {
1384
1385 /**
1386 * The instrumented enumeration type.
1387 */
1388 private final TypeDescription instrumentedType;
1389
1390 /**
1391 * Creates a new appender for the {@code values} method.
1392 *
1393 * @param instrumentedType The instrumented enumeration type.
1394 */
1395 protected ValuesMethodAppender(TypeDescription instrumentedType) {
1396 this.instrumentedType = instrumentedType;
1397 }
1398
1399 /**
1400 * {@inheritDoc}
1401 */
1402 public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1403 FieldDescription valuesField = instrumentedType.getDeclaredFields().filter(named(ENUM_VALUES)).getOnly();
1404 MethodDescription cloneMethod = TypeDescription.Generic.OBJECT.getDeclaredMethods().filter(named(CLONE_METHOD_NAME)).getOnly();
1405 return new Size(new StackManipulation.Compound(
1406 FieldAccess.forField(valuesField).read(),
1407 MethodInvocation.invoke(cloneMethod).virtual(valuesField.getType().asErasure()),
1408 TypeCasting.to(valuesField.getType().asErasure()),
1409 MethodReturn.REFERENCE
1410 ).apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1411 }
1412 }
1413
1414 /**
1415 * A byte code appender for the type initializer of any enumeration type.
1416 */
1417 @HashCodeAndEqualsPlugin.Enhance
1418 protected static class InitializationAppender implements ByteCodeAppender {
1419
1420 /**
1421 * The values of the enumeration that is being created.
1422 */
1423 private final List<String> values;
1424
1425 /**
1426 * Creates an appender for an enumerations type initializer.
1427 *
1428 * @param values The values of the enumeration that is being created.
1429 */
1430 protected InitializationAppender(List<String> values) {
1431 this.values = values;
1432 }
1433
1434 /**
1435 * {@inheritDoc}
1436 */
1437 public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1438 TypeDescription instrumentedType = instrumentedMethod.getDeclaringType().asErasure();
1439 MethodDescription enumConstructor = instrumentedType.getDeclaredMethods()
1440 .filter(isConstructor().and(takesArguments(String.class, int.class)))
1441 .getOnly();
1442 int ordinal = 0;
1443 StackManipulation stackManipulation = StackManipulation.Trivial.INSTANCE;
1444 List<FieldDescription> enumerationFields = new ArrayList<FieldDescription>(values.size());
1445 for (String value : values) {
1446 FieldDescription fieldDescription = instrumentedType.getDeclaredFields().filter(named(value)).getOnly();
1447 stackManipulation = new StackManipulation.Compound(stackManipulation,
1448 TypeCreation.of(instrumentedType),
1449 Duplication.SINGLE,
1450 new TextConstant(value),
1451 IntegerConstant.forValue(ordinal++),
1452 MethodInvocation.invoke(enumConstructor),
1453 FieldAccess.forField(fieldDescription).write());
1454 enumerationFields.add(fieldDescription);
1455 }
1456 List<StackManipulation> fieldGetters = new ArrayList<StackManipulation>(values.size());
1457 for (FieldDescription fieldDescription : enumerationFields) {
1458 fieldGetters.add(FieldAccess.forField(fieldDescription).read());
1459 }
1460 stackManipulation = new StackManipulation.Compound(
1461 stackManipulation,
1462 ArrayFactory.forType(instrumentedType.asGenericType()).withValues(fieldGetters),
1463 FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(ENUM_VALUES)).getOnly()).write()
1464 );
1465 return new Size(stackManipulation.apply(methodVisitor, implementationContext).getMaximalSize(), instrumentedMethod.getStackSize());
1466 }
1467 }
1468 }
1469
1470 /**
1471 * A constructor strategy for implementing a Java record.
1472 */
1473 @HashCodeAndEqualsPlugin.Enhance
1474 protected enum RecordConstructorStrategy implements ConstructorStrategy, Implementation {
1475
1476 /**
1477 * The singleton instance.
1478 */
1479 INSTANCE;
1480
1481 /**
1482 * {@inheritDoc}
1483 */
1484 public List<MethodDescription.Token> extractConstructors(TypeDescription instrumentedType) {
1485 List<ParameterDescription.Token> tokens = new ArrayList<ParameterDescription.Token>(instrumentedType.getRecordComponents().size());
1486 for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1487 tokens.add(new ParameterDescription.Token(recordComponent.getType(),
1488 recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.CONSTRUCTOR))));
1489 }
1490 return Collections.singletonList(new MethodDescription.Token(MethodDescription.CONSTRUCTOR_INTERNAL_NAME,
1491 Opcodes.ACC_PUBLIC,
1492 Collections.<TypeVariableToken>emptyList(),
1493 TypeDescription.Generic.VOID,
1494 tokens,
1495 Collections.<TypeDescription.Generic>emptyList(),
1496 Collections.<AnnotationDescription>emptyList(),
1497 AnnotationValue.UNDEFINED,
1498 TypeDescription.Generic.UNDEFINED));
1499 }
1500
1501 /**
1502 * {@inheritDoc}
1503 */
1504 public MethodRegistry inject(TypeDescription instrumentedType, MethodRegistry methodRegistry) {
1505 return methodRegistry.prepend(new LatentMatcher.Resolved<MethodDescription>(isConstructor().and(takesGenericArguments(instrumentedType.getRecordComponents().asTypeList()))),
1506 new MethodRegistry.Handler.ForImplementation(this),
1507 MethodAttributeAppender.ForInstrumentedMethod.EXCLUDING_RECEIVER,
1508 Transformer.ForMethod.NoOp.<MethodDescription>make());
1509 }
1510
1511 /**
1512 * {@inheritDoc}
1513 */
1514 public ByteCodeAppender appender(Target implementationTarget) {
1515 return new Appender(implementationTarget.getInstrumentedType());
1516 }
1517
1518 /**
1519 * {@inheritDoc}
1520 */
1521 public InstrumentedType prepare(InstrumentedType instrumentedType) {
1522 for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1523 instrumentedType = instrumentedType
1524 .withField(new FieldDescription.Token(recordComponent.getActualName(),
1525 Opcodes.ACC_PRIVATE | Opcodes.ACC_FINAL,
1526 recordComponent.getType(),
1527 recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.FIELD))))
1528 .withMethod(new MethodDescription.Token(recordComponent.getActualName(),
1529 Opcodes.ACC_PUBLIC,
1530 Collections.<TypeVariableToken>emptyList(),
1531 recordComponent.getType(),
1532 Collections.<ParameterDescription.Token>emptyList(),
1533 Collections.<TypeDescription.Generic>emptyList(),
1534 recordComponent.getDeclaredAnnotations().filter(targetsElement(ElementType.METHOD)),
1535 AnnotationValue.UNDEFINED,
1536 TypeDescription.Generic.UNDEFINED));
1537 }
1538 return instrumentedType;
1539 }
1540
1541 /**
1542 * A byte code appender for accessors and the record constructor.
1543 */
1544 @HashCodeAndEqualsPlugin.Enhance
1545 protected static class Appender implements ByteCodeAppender {
1546
1547 /**
1548 * The instrumented type.
1549 */
1550 private final TypeDescription instrumentedType;
1551
1552 /**
1553 * Creates a new byte code appender for accessors and the record constructor.
1554 *
1555 * @param instrumentedType The instrumented type.
1556 */
1557 protected Appender(TypeDescription instrumentedType) {
1558 this.instrumentedType = instrumentedType;
1559 }
1560
1561 /**
1562 * {@inheritDoc}
1563 */
1564 public Size apply(MethodVisitor methodVisitor, Context implementationContext, MethodDescription instrumentedMethod) {
1565 if (instrumentedMethod.isMethod()) {
1566 return new Simple(
1567 MethodVariableAccess.loadThis(),
1568 FieldAccess.forField(instrumentedType.getDeclaredFields().filter(named(instrumentedMethod.getName())).getOnly()).read(),
1569 MethodReturn.of(instrumentedMethod.getReturnType())
1570 ).apply(methodVisitor, implementationContext, instrumentedMethod);
1571 } else {
1572 List<StackManipulation> stackManipulations = new ArrayList<StackManipulation>(instrumentedType.getRecordComponents().size() * 3 + 2);
1573 stackManipulations.add(MethodVariableAccess.loadThis());
1574 stackManipulations.add(MethodInvocation.invoke(new MethodDescription.Latent(JavaType.RECORD.getTypeStub(), new MethodDescription.Token(Opcodes.ACC_PUBLIC))));
1575 int offset = 1;
1576 for (RecordComponentDescription.InDefinedShape recordComponent : instrumentedType.getRecordComponents()) {
1577 stackManipulations.add(MethodVariableAccess.loadThis());
1578 stackManipulations.add(MethodVariableAccess.of(recordComponent.getType()).loadFrom(offset));
1579 stackManipulations.add(FieldAccess.forField(instrumentedType.getDeclaredFields()
1580 .filter(named(recordComponent.getActualName()))
1581 .getOnly()).write());
1582 offset += recordComponent.getType().getStackSize().getSize();
1583 }
1584 stackManipulations.add(MethodReturn.VOID);
1585 return new Simple(stackManipulations).apply(methodVisitor, implementationContext, instrumentedMethod);
1586 }
1587 }
1588 }
1589 }
1590
1591 /**
1592 * Implements the object methods of the Java record type.
1593 */
1594 @HashCodeAndEqualsPlugin.Enhance
1595 protected enum RecordObjectMethod implements Implementation {
1596
1597 /**
1598 * The {@code hashCode} method.
1599 */
1600 HASH_CODE("hashCode", StackManipulation.Trivial.INSTANCE, int.class),
1601
1602 /**
1603 * The {@code equals} method.
1604 */
1605 EQUALS("equals", MethodVariableAccess.REFERENCE.loadFrom(1), boolean.class, Object.class),
1606
1607 /**
1608 * The {@code toString} method.
1609 */
1610 TO_STRING("toString", StackManipulation.Trivial.INSTANCE, String.class);
1611
1612 /**
1613 * The method name.
1614 */
1615 private final String name;
1616
1617 /**
1618 * The stack manipulation to append to the arguments.
1619 */
1620 private final StackManipulation stackManipulation;
1621
1622 /**
1623 * The return type.
1624 */
1625 private final TypeDescription returnType;
1626
1627 /**
1628 * The arguments type.
1629 */
1630 private final List<? extends TypeDescription> arguments;
1631
1632 /**
1633 * Creates a new object method instance for a Java record.
1634 *
1635 * @param name The method name.
1636 * @param stackManipulation The stack manipulation to append to the arguments.
1637 * @param returnType The return type.
1638 * @param arguments The arguments type.
1639 */
1640 RecordObjectMethod(String name, StackManipulation stackManipulation, Class<?> returnType, Class<?>... arguments) {
1641 this.name = name;
1642 this.stackManipulation = stackManipulation;
1643 this.returnType = TypeDescription.ForLoadedType.of(returnType);
1644 this.arguments = new TypeList.ForLoadedTypes(arguments);
1645 }
1646
1647 /**
1648 * {@inheritDoc}
1649 */
1650 public ByteCodeAppender appender(Target implementationTarget) {
1651 StringBuilder stringBuilder = new StringBuilder();
1652 List<Object> methodHandles = new ArrayList<Object>(implementationTarget.getInstrumentedType().getRecordComponents().size());
1653 for (RecordComponentDescription.InDefinedShape recordComponent : implementationTarget.getInstrumentedType().getRecordComponents()) {
1654 if (stringBuilder.length() > 0) {
1655 stringBuilder.append(";");
1656 }
1657 stringBuilder.append(recordComponent.getActualName());
1658 methodHandles.add(JavaConstant.MethodHandle.ofGetter(implementationTarget.getInstrumentedType().getDeclaredFields()
1659 .filter(named(recordComponent.getActualName()))
1660 .getOnly()).asConstantPoolValue());
1661 }
1662 return new ByteCodeAppender.Simple(MethodVariableAccess.loadThis(),
1663 stackManipulation,
1664 MethodInvocation.invoke(new MethodDescription.Latent(JavaType.OBJECT_METHODS.getTypeStub(), new MethodDescription.Token("bootstrap",
1665 Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC,
1666 TypeDescription.Generic.OBJECT,
1667 Arrays.asList(JavaType.METHOD_HANDLES_LOOKUP.getTypeStub().asGenericType(),
1668 TypeDescription.STRING.asGenericType(),
1669 JavaType.TYPE_DESCRIPTOR.getTypeStub().asGenericType(),
1670 TypeDescription.CLASS.asGenericType(),
1671 TypeDescription.STRING.asGenericType(),
1672 TypeDescription.ArrayProjection.of(JavaType.METHOD_HANDLE.getTypeStub()).asGenericType())))).dynamic(name,
1673 returnType,
1674 CompoundList.of(implementationTarget.getInstrumentedType(), arguments),
1675 CompoundList.of(Arrays.asList(net.bytebuddy.jar.asm.Type.getType(implementationTarget.getInstrumentedType().getDescriptor()), stringBuilder.toString()), methodHandles)),
1676 MethodReturn.of(returnType));
1677 }
1678
1679 /**
1680 * {@inheritDoc}
1681 */
1682 public InstrumentedType prepare(InstrumentedType instrumentedType) {
1683 return instrumentedType;
1684 }
1685 }
1686 }
1687