All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ui4j.bytebuddy.ByteBuddy Maven / Gradle / Ivy

The newest version!
package com.ui4j.bytebuddy;

import com.ui4j.bytebuddy.asm.ClassVisitorWrapper;
import com.ui4j.bytebuddy.dynamic.ClassFileLocator;
import com.ui4j.bytebuddy.dynamic.DynamicType;
import com.ui4j.bytebuddy.dynamic.scaffold.BridgeMethodResolver;
import com.ui4j.bytebuddy.dynamic.scaffold.FieldRegistry;
import com.ui4j.bytebuddy.dynamic.scaffold.MethodRegistry;
import com.ui4j.bytebuddy.dynamic.scaffold.inline.InlineDynamicTypeBuilder;
import com.ui4j.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver;
import com.ui4j.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy;
import com.ui4j.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder;
import com.ui4j.bytebuddy.instrumentation.Instrumentation;
import com.ui4j.bytebuddy.instrumentation.ModifierContributor;
import com.ui4j.bytebuddy.instrumentation.attribute.FieldAttributeAppender;
import com.ui4j.bytebuddy.instrumentation.attribute.MethodAttributeAppender;
import com.ui4j.bytebuddy.instrumentation.attribute.TypeAttributeAppender;
import com.ui4j.bytebuddy.instrumentation.method.MethodDescription;
import com.ui4j.bytebuddy.instrumentation.method.MethodLookupEngine;
import com.ui4j.bytebuddy.instrumentation.type.TypeDescription;
import com.ui4j.bytebuddy.instrumentation.type.TypeList;
import com.ui4j.bytebuddy.matcher.ElementMatcher;
import com.ui4j.bytebuddy.modifier.TypeManifestation;
import com.ui4j.bytebuddy.jar.asm.Opcodes;

import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static com.ui4j.bytebuddy.matcher.ElementMatchers.*;
import static com.ui4j.bytebuddy.utility.ByteBuddyCommons.*;

/**
 * {@code ByteBuddy} instances are configurable factories for creating new Java types at a JVM's runtime.
 * Such types are represented by {@link com.ui4j.bytebuddy.dynamic.DynamicType}s which can be saved to disk or loaded into
 * the Java virtual machine. Each instance of {@code ByteBuddy} is immutable where any of the factory methods returns
 * a new instance that represents the altered configuration.
 * 

 

* Note that any configuration defines to ignore the instrumentation of any synthetic methods or the default finalizer * method {@link Object#finalize()}. This behavior can be altered by * {@link com.ui4j.bytebuddy.ByteBuddy#withIgnoredMethods(com.ui4j.bytebuddy.matcher.ElementMatcher)}. */ public class ByteBuddy { /** * The default prefix for the default {@link com.ui4j.bytebuddy.NamingStrategy}. */ public static final String BYTE_BUDDY_DEFAULT_PREFIX = "ByteBuddy"; /** * The class file version of the current configuration. */ protected final ClassFileVersion classFileVersion; /** * The naming strategy of the current configuration. */ protected final NamingStrategy.Unbound namingStrategy; /** * A list of interface types to be implemented by any class that is implemented by the current configuration. */ protected final List interfaceTypes; /** * A matcher for identifying methods that should never be intercepted. */ protected final ElementMatcher ignoredMethods; /** * The factory for generating a bridge method resolver for the current configuration. */ protected final BridgeMethodResolver.Factory bridgeMethodResolverFactory; /** * The class visitor wrapper chain for the current configuration. */ protected final ClassVisitorWrapper.Chain classVisitorWrapperChain; /** * The method registry for the current configuration. */ protected final MethodRegistry methodRegistry; /** * The modifiers to apply to any type that is generated by this configuration. */ protected final Definable modifiers; /** * The method lookup engine factory to apply to any type that is generated by this configuration. */ protected final MethodLookupEngine.Factory methodLookupEngineFactory; /** * The type attribute appender factory to apply to any type that is generated by this configuration. */ protected final TypeAttributeAppender typeAttributeAppender; /** * The default field attribute appender factory which is applied to any field that is defined * for instrumentations that are applied by this configuration. */ protected final FieldAttributeAppender.Factory defaultFieldAttributeAppenderFactory; /** * The default method attribute appender factory which is applied to any method that is defined * or intercepted for instrumentations that are applied by this configuration. */ protected final MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory; /** * Defines a new {@code ByteBuddy} default configuration for the current Java virtual machine's * class file version. */ public ByteBuddy() { this(ClassFileVersion.forCurrentJavaVersion()); } /** * Defines a new {@code ByteBuddy} default configuration for the given class file version. * * @param classFileVersion The class file version to apply. */ public ByteBuddy(ClassFileVersion classFileVersion) { this(nonNull(classFileVersion), new NamingStrategy.Unbound.Default(BYTE_BUDDY_DEFAULT_PREFIX), new TypeList.Empty(), isDefaultFinalizer().or(isSynthetic().and(not(isVisibilityBridge()))), BridgeMethodResolver.Simple.Factory.FAIL_ON_REQUEST, new ClassVisitorWrapper.Chain(), new MethodRegistry.Default(), new Definable.Undefined(), TypeAttributeAppender.NoOp.INSTANCE, MethodLookupEngine.Default.Factory.INSTANCE, FieldAttributeAppender.NoOp.INSTANCE, MethodAttributeAppender.NoOp.INSTANCE); } /** * Defines a new {@code ByteBuddy} configuration. * * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param interfaceTypes The currently defined collection of interfaces to be implemented * by any dynamically created type. * @param ignoredMethods The methods to always be ignored. * @param bridgeMethodResolverFactory The bridge method resolver factory to be applied to any instrumentation * process. * @param classVisitorWrapperChain The class visitor wrapper chain to be applied to any instrumentation * process. * @param methodRegistry The currently valid method registry. * @param modifiers The modifiers to define for any instrumentation process. * @param typeAttributeAppender The type attribute appender to apply to any instrumentation process. * @param methodLookupEngineFactory The method lookup engine factory to apply to this configuration. * @param defaultFieldAttributeAppenderFactory The field attribute appender to apply as a default for any field * definition. * @param defaultMethodAttributeAppenderFactory The method attribute appender to apply as a default for any * method definition or instrumentation. */ protected ByteBuddy(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, List interfaceTypes, ElementMatcher ignoredMethods, BridgeMethodResolver.Factory bridgeMethodResolverFactory, ClassVisitorWrapper.Chain classVisitorWrapperChain, MethodRegistry methodRegistry, Definable modifiers, TypeAttributeAppender typeAttributeAppender, MethodLookupEngine.Factory methodLookupEngineFactory, FieldAttributeAppender.Factory defaultFieldAttributeAppenderFactory, MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory) { this.classFileVersion = classFileVersion; this.namingStrategy = namingStrategy; this.interfaceTypes = interfaceTypes; this.ignoredMethods = ignoredMethods; this.bridgeMethodResolverFactory = bridgeMethodResolverFactory; this.classVisitorWrapperChain = classVisitorWrapperChain; this.methodRegistry = methodRegistry; this.modifiers = modifiers; this.typeAttributeAppender = typeAttributeAppender; this.methodLookupEngineFactory = methodLookupEngineFactory; this.defaultFieldAttributeAppenderFactory = defaultFieldAttributeAppenderFactory; this.defaultMethodAttributeAppenderFactory = defaultMethodAttributeAppenderFactory; } /** * Returns the class file version that is defined for the current configuration. * * @return The class file version that is defined for this configuration. */ public ClassFileVersion getClassFileVersion() { return classFileVersion; } /** * Returns the naming strategy for the current configuration. * * @return The naming strategy for the current configuration. */ public NamingStrategy.Unbound getNamingStrategy() { return namingStrategy; } /** * Returns the naming strategy for the current configuration. * * @return The naming strategy for the current configuration. */ public List getInterfaceTypes() { return Collections.unmodifiableList(interfaceTypes); } /** * Returns the matcher for the ignored methods for the current configuration. * * @return The matcher for the ignored methods for the current configuration. */ public ElementMatcher getIgnoredMethods() { return ignoredMethods; } /** * Returns the factory for the bridge method resolver for the current configuration. * * @return The factory for the bridge method resolver for the current configuration. */ public BridgeMethodResolver.Factory getBridgeMethodResolverFactory() { return bridgeMethodResolverFactory; } /** * Returns the class visitor wrapper chain for the current configuration. * * @return The class visitor wrapper chain for the current configuration. */ public ClassVisitorWrapper.Chain getClassVisitorWrapperChain() { return classVisitorWrapperChain; } /** * Returns the method registry for the current configuration. * * @return The method registry for the current configuration. */ public MethodRegistry getMethodRegistry() { return methodRegistry; } /** * Returns the modifiers to apply to any type that is generated by this configuration. * * @return The modifiers to apply to any type that is generated by this configuration. */ public Definable getModifiers() { return modifiers; } /** * Returns the method lookup engine factory to apply to any type that is generated by this configuration. * * @return The method lookup engine factory to apply to any type that is generated by this configuration. */ public MethodLookupEngine.Factory getMethodLookupEngineFactory() { return methodLookupEngineFactory; } /** * Returns the type attribute appender factory to apply to any type that is generated by this configuration. * * @return The type attribute appender factory to apply to any type that is generated by this configuration. */ public TypeAttributeAppender getTypeAttributeAppender() { return typeAttributeAppender; } /** * Returns the default field attribute appender factory which is applied to any field that is defined * for instrumentations that are applied by this configuration. * * @return The default field attribute appender factory which is applied to any field that is defined * for instrumentations that are applied by this configuration. */ public FieldAttributeAppender.Factory getDefaultFieldAttributeAppenderFactory() { return defaultFieldAttributeAppenderFactory; } /** * Returns the default method attribute appender factory which is applied to any method that is defined * or intercepted for instrumentations that are applied by this configuration. * * @return The default method attribute appender factory which is applied to any method that is defined * or intercepted for instrumentations that are applied by this configuration. */ public MethodAttributeAppender.Factory getDefaultMethodAttributeAppenderFactory() { return defaultMethodAttributeAppenderFactory; } /** * Creates a dynamic type builder that creates a subclass of a given loaded type where the subclass * is created by the {@link com.ui4j.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy.Default#IMITATE_SUPER_TYPE} * strategy. * * @param superType The type or interface to be extended or implemented by the dynamic type. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that extends or implements the given loaded type. */ public DynamicType.Builder subclass(Class superType) { return subclass(new TypeDescription.ForLoadedType(nonNull(superType))); } /** * Creates a dynamic type builder that creates a subclass of a given loaded type. * * @param superType The type or interface to be extended or implemented by the dynamic type. * @param constructorStrategy The constructor strategy to apply. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that extends or implements the given loaded type. */ public DynamicType.Builder subclass(Class superType, ConstructorStrategy constructorStrategy) { return subclass(new TypeDescription.ForLoadedType(nonNull(superType)), constructorStrategy); } /** * Creates a dynamic type builder that creates a subclass of a given type description where the subclass * is created by the {@link com.ui4j.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy.Default#IMITATE_SUPER_TYPE} * strategy. * * @param superType The type or interface to be extended or implemented by the dynamic type. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that extends or implements the given type description. */ public DynamicType.Builder subclass(TypeDescription superType) { return subclass(superType, ConstructorStrategy.Default.IMITATE_SUPER_TYPE); } /** * Creates a dynamic type builder that creates a subclass of a given type description. * * @param superType The type or interface to be extended or implemented by the dynamic type. * @param constructorStrategy The constructor strategy to apply. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that extends or implements the given type description. */ public DynamicType.Builder subclass(TypeDescription superType, ConstructorStrategy constructorStrategy) { TypeDescription actualSuperType = isExtendable(superType); List interfaceTypes = this.interfaceTypes; if (nonNull(superType).isInterface()) { actualSuperType = new TypeDescription.ForLoadedType(Object.class); interfaceTypes = join(superType, interfaceTypes); } return new SubclassDynamicTypeBuilder(classFileVersion, nonNull(namingStrategy.subclass(superType)), actualSuperType, interfaceTypes, modifiers.resolve(superType.getModifiers() & ~TypeManifestation.INTERFACE.getMask()), typeAttributeAppender, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, new FieldRegistry.Default(), methodRegistry, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, nonNull(constructorStrategy)); } /** * Creates a dynamic type builder for an interface that extends the given interface. * * @param type The interface to extend. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that defines an interface that extends the specified * interface. */ @SuppressWarnings("unchecked") public DynamicType.Builder makeInterface(Class type) { return (DynamicType.Builder) makeInterface(new TypeDescription.ForLoadedType(nonNull(type))); } /** * Creates a dynamic type builder for an interface that extends a number of given interfaces. * * @param type The interface types to extend. * @return A dynamic type builder for this configuration that defines an interface that extends the specified * interfaces. */ public DynamicType.Builder makeInterface(Class... type) { return makeInterface(new TypeList.ForLoadedType(nonNull(type))); } /** * Creates a dynamic type builder for an interface that extends a number of given interface. * * @param typeDescription The interface type to extend. * @return A dynamic type builder for this configuration that defines an interface that extends the specified * interface. */ public DynamicType.Builder makeInterface(TypeDescription typeDescription) { return makeInterface(Arrays.asList(nonNull(typeDescription))); } /** * Creates a dynamic type builder for an interface that extends a number of given interfaces. * * @param typeDescriptions The interface types to extend. * @return A dynamic type builder for this configuration that defines an interface that extends the specified * interfaces. */ public DynamicType.Builder makeInterface(List typeDescriptions) { return new SubclassDynamicTypeBuilder(classFileVersion, namingStrategy.subclass(new TypeDescription.ForLoadedType(Object.class)), new TypeDescription.ForLoadedType(Object.class), join(interfaceTypes, nonNull(typeDescriptions)), modifiers.resolve(Opcodes.ACC_INTERFACE | Opcodes.ACC_ABSTRACT | Opcodes.ACC_PUBLIC), typeAttributeAppender, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, new FieldRegistry.Default(), methodRegistry, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, ConstructorStrategy.Default.NO_CONSTRUCTORS); } /** *

* Creates a dynamic type builder for redefining of the given type. The given class must be found on the * class path or by the class's {@link java.lang.ClassLoader}. Otherwise, the class file to the redefined class * must be located explicitly by providing a locator by * {@link com.ui4j.bytebuddy.ByteBuddy#redefine(Class, com.ui4j.bytebuddy.dynamic.ClassFileLocator)}. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is redefined several times without providing an updated * version of the class file. *

* * @param levelType The type to redefine. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that redefines the given type description. */ public DynamicType.Builder redefine(Class levelType) { return redefine(levelType, ClassFileLocator.ForClassLoader.of(levelType.getClassLoader())); } /** *

* Creates a dynamic type builder for redefining of the given type. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is redefined several times without providing an updated * version of the class file. *

* * @param levelType The type to redefine. * @param classFileLocator A locator for finding a class file that represents a type. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that redefines the given type description. */ public DynamicType.Builder redefine(Class levelType, ClassFileLocator classFileLocator) { return redefine(new TypeDescription.ForLoadedType(nonNull(levelType)), classFileLocator); } /** *

* Creates a dynamic type builder for redefining of the given type. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is redefined several times without providing an updated * version of the class file. *

* * @param levelType The type to redefine. * @param classFileLocator A locator for finding a class file that represents a type. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that redefines the given type description. */ public DynamicType.Builder redefine(TypeDescription levelType, ClassFileLocator classFileLocator) { return new InlineDynamicTypeBuilder(classFileVersion, nonNull(namingStrategy.redefine(levelType)), nonNull(levelType), interfaceTypes, modifiers.resolve(levelType.getModifiers()), typeAttributeAppender, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, new FieldRegistry.Default(), methodRegistry, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, nonNull(classFileLocator), InlineDynamicTypeBuilder.TargetHandler.ForRedefinitionInstrumentation.INSTANCE); } /** *

* Creates a dynamic type by weaving any changes into an already defined level type. The rebased type is * created by adding methods to the level type where the original method implementations are copied to * renamed, private methods within the created dynamic type and therefore remain invokable as super method calls. * The result is a rebased type with subclass semantics. The given class must be found on the class path or * by the provided class's {@link java.lang.ClassLoader}. Otherwise, the class file to the redefined class * must be located explicitly by providing a locator by * {@link com.ui4j.bytebuddy.ByteBuddy#rebase(Class, com.ui4j.bytebuddy.dynamic.ClassFileLocator)}. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is rebased several times without updating the class file. *

* * @param levelType The type which is to be rebased. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that creates a rebased version of the given type. */ public DynamicType.Builder rebase(Class levelType) { return rebase(levelType, ClassFileLocator.ForClassLoader.of(levelType.getClassLoader())); } /** *

* Creates a dynamic type by weaving any changes into an already defined level type. The rebased type is * created by adding methods to the level type where the original method implementations are copied to * renamed, private methods within the created dynamic type and therefore remain invokable as super method calls. * The result is a rebased type with subclass semantics. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is rebased several times without updating the class file. *

* * @param levelType The type which is to be rebased. * @param classFileLocator A locator for finding a class file that represents a type. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that creates a rebased version of the given type. */ public DynamicType.Builder rebase(Class levelType, ClassFileLocator classFileLocator) { return rebase(new TypeDescription.ForLoadedType(nonNull(levelType)), classFileLocator); } /** *

* Creates a dynamic type by weaving any changes into an already defined level type. The rebased type is * created by adding methods to the level type where the original method implementations are copied to * renamed, private methods within the created dynamic type and therefore remain invokable as super method calls. * The result is a rebased type with subclass semantics. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is rebased several times without updating the class file. *

* * @param levelType The type which is to be rebased. * @param classFileLocator A locator for finding a class file that represents a type. * @param methodNameTransformer The method name transformer that is used for rebasing methods. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that creates a rebased version of the given type. */ public DynamicType.Builder rebase(Class levelType, ClassFileLocator classFileLocator, MethodRebaseResolver.MethodNameTransformer methodNameTransformer) { return rebase(new TypeDescription.ForLoadedType(nonNull(levelType)), classFileLocator, methodNameTransformer); } /** *

* Creates a dynamic type by weaving any changes into an already defined level type. The rebased type is * created by adding methods to the level type where the original method implementations are copied to * renamed, private methods within the created dynamic type and therefore remain invokable as super method calls. * The result is a rebased type with subclass semantics. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is rebased several times without updating the class file. *

* * @param levelType The type which is to be rebased. * @param classFileLocator A locator for finding a class file that represents a type. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that creates a rebased version of the given type. */ public DynamicType.Builder rebase(TypeDescription levelType, ClassFileLocator classFileLocator) { return rebase(levelType, classFileLocator, new MethodRebaseResolver.MethodNameTransformer.Suffixing()); } /** *

* Creates a dynamic type by weaving any changes into an already defined level type. The rebased type is * created by adding methods to the level type where the original method implementations are copied to * renamed, private methods within the created dynamic type and therefore remain invokable as super method calls. * The result is a rebased type with subclass semantics. *

*

* Note: It is possible to experience unexpected errors in case that the provided {@code levelType} and the * corresponding class file get out of sync, i.e. a type is rebased several times without updating the class file. *

* * @param levelType The type which is to be rebased. * @param classFileLocator A locator for finding a class file that represents a type. * @param methodNameTransformer The method name transformer that is used for rebasing methods. * @param The most specific known type that the created dynamic type represents. * @return A dynamic type builder for this configuration that creates a rebased version of the given type. */ public DynamicType.Builder rebase(TypeDescription levelType, ClassFileLocator classFileLocator, MethodRebaseResolver.MethodNameTransformer methodNameTransformer) { return new InlineDynamicTypeBuilder(classFileVersion, nonNull(namingStrategy.rebase(levelType)), levelType, interfaceTypes, modifiers.resolve(levelType.getModifiers()), TypeAttributeAppender.NoOp.INSTANCE, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, new FieldRegistry.Default(), methodRegistry, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, nonNull(classFileLocator), new InlineDynamicTypeBuilder.TargetHandler.ForRebaseInstrumentation(nonNull(methodNameTransformer))); } /** * Defines a new class file version for this configuration. * * @param classFileVersion The class file version to define for this configuration. * @return A new configuration that represents this configuration with the given class file version. */ public ByteBuddy withClassFileVersion(ClassFileVersion classFileVersion) { return new ByteBuddy(nonNull(classFileVersion), namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new naming strategy for this configuration. * * @param namingStrategy The unbound naming strategy to apply to the current configuration. * @return A new configuration that represents this configuration with the given unbound naming strategy. */ public ByteBuddy withNamingStrategy(NamingStrategy.Unbound namingStrategy) { return new ByteBuddy(classFileVersion, nonNull(namingStrategy), interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new naming strategy for this configuration. * * @param namingStrategy The naming strategy to apply to the current configuration. * @return A new configuration that represents this configuration with the given naming strategy. */ public ByteBuddy withNamingStrategy(NamingStrategy namingStrategy) { return withNamingStrategy(new NamingStrategy.Unbound.Unified(nonNull(namingStrategy))); } /** * Defines a new modifier contributors for this configuration that replaces the currently defined modifier * contributes which might currently be implicit. * * @param modifierContributor The modifier contributors to define explicitly for this configuration. * @return A new configuration that represents this configuration with the given modifier contributors. */ public ByteBuddy withModifiers(ModifierContributor.ForType... modifierContributor) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, new Definable.Defined( resolveModifierContributors(TYPE_MODIFIER_MASK, nonNull(modifierContributor))), typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new type attribute appender for this configuration that replaces the currently defined type * attribute appender. * * @param typeAttributeAppender The type attribute appender to define for this configuration. * @return A new configuration that represents this configuration with the given type attribute appender. */ public ByteBuddy withAttribute(TypeAttributeAppender typeAttributeAppender) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, nonNull(typeAttributeAppender), methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new type annotation for this configuration that replaces the currently defined type * attribute appender. * * @param annotation The type annotations to define for this configuration. * @return A new configuration that represents this configuration with the given annotations as its new * type attribute appender. */ public ByteBuddy withTypeAnnotation(Annotation... annotation) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, new TypeAttributeAppender.ForAnnotation(nonNull(annotation)), methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines all dynamic types that are created by this configuration to implement the given interface. * * @param type The interface type to implement. * @return This configuration where any dynamic type that is created by the resulting configuration will * implement the given interface. */ public OptionalMethodInterception withImplementing(Class... type) { TypeDescription[] typeDescription = new TypeDescription[type.length]; int index = 0; for (Class aType : type) { typeDescription[index++] = new TypeDescription.ForLoadedType(aType); } return withImplementing(typeDescription); } /** * Defines all dynamic types that are created by this configuration to implement the given interface. * * @param type The interface type to implement. * @return The same configuration where any dynamic type that is created by the resulting configuration will * implement the given interface. */ public OptionalMethodInterception withImplementing(TypeDescription... type) { return new OptionalMethodInterception(classFileVersion, namingStrategy, join(interfaceTypes, isInterface(Arrays.asList(type))), ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, isDeclaredBy(anyOf((Object[]) type))); } /** * Defines a new method matcher for methods that are ignored by any dynamic type that is created by this * configuration which will replace the current configuration. By default, this method matcher is defined * to ignore instrumenting synthetic methods and the default finalizer method. The only exception from per-default * overridable synthetic methods are bridge methods which is only implemented by the Java compiler to increase a * method's visibility. * * @param ignoredMethods The methods to always be ignored for any instrumentation. * @return A new configuration that represents this configuration with the given method matcher defining methods * that are to be ignored for any instrumentation. */ public ByteBuddy withIgnoredMethods(ElementMatcher ignoredMethods) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, nonNull(ignoredMethods), bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a bridge method resolver factory to be applied to this configuration. A bridge method resolver is * responsible for determining the target method that is invoked by a bridge method. This way, a super method * invocation is resolved by invoking the actual super method instead of the bridge method which would in turn * resolve the actual method virtually. * * @param bridgeMethodResolverFactory The bridge method resolver factory to be applied to any instrumentation * process. * @return A new configuration that represents this configuration with the given bridge method resolver factory * to be applied on any configuration. */ public ByteBuddy withBridgeMethodResolver(BridgeMethodResolver.Factory bridgeMethodResolverFactory) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, nonNull(bridgeMethodResolverFactory), classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new class visitor to be appended to the current collection of {@link com.ui4j.bytebuddy.jar.asm.ClassVisitor}s * that are to be applied onto any creation process of a dynamic type. * * @param classVisitorWrapper The class visitor wrapper to ba appended to the current chain of class visitor wrappers. * @return The same configuration with the given class visitor wrapper to be applied onto any creation process of a dynamic * type. */ public ByteBuddy withClassVisitor(ClassVisitorWrapper classVisitorWrapper) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain.append(nonNull(classVisitorWrapper)), methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new {@link com.ui4j.bytebuddy.instrumentation.method.MethodLookupEngine.Factory} to be used for creating * {@link com.ui4j.bytebuddy.instrumentation.method.MethodLookupEngine}s for type creations based on this configuration. * The default lookup engine queries any class or interface type that is represented by the created type. These * queries might however be costly such that this factory can be configured to save lookup time, for example * by providing additional caching or by providing precomputed results. * * @param methodLookupEngineFactory The method lookup engine factory to apply to this configuration. * @return The same configuration with the method lookup engine factory. */ public ByteBuddy withMethodLookupEngine(MethodLookupEngine.Factory methodLookupEngineFactory) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, nonNull(methodLookupEngineFactory), defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } /** * Defines a new default field attribute appender factory that is applied onto any field. * * @param attributeAppenderFactory The attribute appender factory that is applied as a default on any * field that is created by a dynamic type that is created with this * configuration. * @return The same configuration with the given field attribute appender factory to be applied as a default to * the creation process of any field of a dynamic type. */ public ByteBuddy withDefaultFieldAttributeAppender(FieldAttributeAppender.Factory attributeAppenderFactory) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, nonNull(attributeAppenderFactory), defaultMethodAttributeAppenderFactory); } /** * Defines a new default method attribute appender factory that is applied onto any method. * * @param attributeAppenderFactory The attribute appender factory that is applied as a default on any * method that is created or intercepted by a dynamic type that is created * with this configuration. * @return The same configuration with the given method attribute appender factory to be applied as a default to * the creation or interception process of any method of a dynamic type. */ public ByteBuddy withDefaultMethodAttributeAppender(MethodAttributeAppender.Factory attributeAppenderFactory) { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, nonNull(attributeAppenderFactory)); } /** * Intercepts a given selection of byte code methods that can be a method or a constructor. * * @param methodMatcher The method matcher representing all byte code methods to intercept. * @return A matched method interception for the given selection. */ public MatchedMethodInterception invokable(ElementMatcher methodMatcher) { return new MatchedMethodInterception(nonNull(methodMatcher)); } /** * Intercepts a given method selection. * * @param methodMatcher The method matcher representing all methods to intercept. * @return A matched method interception for the given selection. */ public MatchedMethodInterception method(ElementMatcher methodMatcher) { return invokable(isMethod().and(nonNull(methodMatcher))); } /** * Intercepts a given constructor selection. * * @param methodMatcher The method matcher representing all constructors to intercept. * @return A matched method interception for the given selection. */ public MatchedMethodInterception constructor(ElementMatcher methodMatcher) { return invokable(isConstructor().and(nonNull(methodMatcher))); } @Override public boolean equals(Object other) { if (this == other) return true; if (other == null || getClass() != other.getClass()) return false; ByteBuddy byteBuddy = (ByteBuddy) other; return bridgeMethodResolverFactory.equals(byteBuddy.bridgeMethodResolverFactory) && classFileVersion.equals(byteBuddy.classFileVersion) && classVisitorWrapperChain.equals(byteBuddy.classVisitorWrapperChain) && defaultFieldAttributeAppenderFactory.equals(byteBuddy.defaultFieldAttributeAppenderFactory) && defaultMethodAttributeAppenderFactory.equals(byteBuddy.defaultMethodAttributeAppenderFactory) && ignoredMethods.equals(byteBuddy.ignoredMethods) && interfaceTypes.equals(byteBuddy.interfaceTypes) && methodLookupEngineFactory.equals(byteBuddy.methodLookupEngineFactory) && methodRegistry.equals(byteBuddy.methodRegistry) && modifiers.equals(byteBuddy.modifiers) && namingStrategy.equals(byteBuddy.namingStrategy) && typeAttributeAppender.equals(byteBuddy.typeAttributeAppender); } @Override public int hashCode() { int result = classFileVersion.hashCode(); result = 31 * result + namingStrategy.hashCode(); result = 31 * result + interfaceTypes.hashCode(); result = 31 * result + ignoredMethods.hashCode(); result = 31 * result + bridgeMethodResolverFactory.hashCode(); result = 31 * result + classVisitorWrapperChain.hashCode(); result = 31 * result + methodRegistry.hashCode(); result = 31 * result + modifiers.hashCode(); result = 31 * result + methodLookupEngineFactory.hashCode(); result = 31 * result + typeAttributeAppender.hashCode(); result = 31 * result + defaultFieldAttributeAppenderFactory.hashCode(); result = 31 * result + defaultMethodAttributeAppenderFactory.hashCode(); return result; } @Override public String toString() { return "ByteBuddy{" + "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", interfaceTypes=" + interfaceTypes + ", ignoredMethods=" + ignoredMethods + ", bridgeMethodResolverFactory=" + bridgeMethodResolverFactory + ", classVisitorWrapperChain=" + classVisitorWrapperChain + ", methodRegistry=" + methodRegistry + ", modifiers=" + modifiers + ", methodLookupEngineFactory=" + methodLookupEngineFactory + ", typeAttributeAppender=" + typeAttributeAppender + ", defaultFieldAttributeAppenderFactory=" + defaultFieldAttributeAppenderFactory + ", defaultMethodAttributeAppenderFactory=" + defaultMethodAttributeAppenderFactory + '}'; } /** * Any definable instance is either {@link com.ui4j.bytebuddy.ByteBuddy.Definable.Defined} when a value is provided * or {@link com.ui4j.bytebuddy.ByteBuddy.Definable.Undefined} if a value is not provided. A defined definable will * return its defined value on request while an undefined definable will return the provided default. * * @param The type of the definable object. */ protected static interface Definable { /** * Returns the value of this instance or the provided default value for an undefined definable. * * @param defaultValue The default value that is returned for an {@link com.ui4j.bytebuddy.ByteBuddy.Definable.Undefined} * definable. * @return The value that is represented by this instance. */ T resolve(T defaultValue); /** * Checks if this value is explicitly defined. * * @return {@code true} if this value is defined. */ boolean isDefined(); /** * A representation of an undefined {@link com.ui4j.bytebuddy.ByteBuddy.Definable}. * * @param The type of the definable object. */ static class Undefined implements Definable { @Override public T resolve(T defaultValue) { return defaultValue; } @Override public boolean isDefined() { return false; } @Override public boolean equals(Object other) { return other != null && other.getClass() == Undefined.class; } @Override public int hashCode() { return 31; } @Override public String toString() { return "ByteBuddy.Definable.Undefined{}"; } } /** * A representation of a defined {@link com.ui4j.bytebuddy.ByteBuddy.Definable} for a given value. * * @param The type of the definable object. */ static class Defined implements Definable { /** * The value that is represented by this defined definable. */ private final T value; /** * Creates a new defined instance for the given value. * * @param value The defined value. */ public Defined(T value) { this.value = value; } @Override public T resolve(T defaultValue) { return value; } @Override public boolean isDefined() { return true; } @Override public boolean equals(Object o) { return this == o || !(o == null || getClass() != o.getClass()) && value.equals(((Defined) o).value); } @Override public int hashCode() { return value.hashCode(); } @Override public String toString() { return "ByteBuddy.Definable.Defined{value=" + value + '}'; } } } /** * Implementations of this interface are capable of defining a method interception for a given set of methods. */ public static interface MethodInterceptable { /** * Intercepts the given method with the given instrumentation. * * @param instrumentation The instrumentation to apply to the selected methods. * @return A method annotation target for this instance with the given instrumentation applied to the * current selection. */ MethodAnnotationTarget intercept(Instrumentation instrumentation); /** * Defines the currently selected methods as {@code abstract}. * * @return A method annotation target for this instance with implementing the currently selected methods * as {@code abstract}. */ MethodAnnotationTarget withoutCode(); } /** * A {@link com.ui4j.bytebuddy.ByteBuddy} configuration with a selected set of methods for which annotations can * be defined. */ public static class MethodAnnotationTarget extends Proxy { /** * The method matcher representing the current method selection. */ protected final ElementMatcher methodMatcher; /** * The instrumentation that was defined for the current method selection. */ protected final Instrumentation instrumentation; /** * The method attribute appender factory that was defined for the current method selection. */ protected final MethodAttributeAppender.Factory attributeAppenderFactory; /** * Creates a new method annotation target. * * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param interfaceTypes The currently defined collection of interfaces to be implemented * by any dynamically created type. * @param ignoredMethods The methods to always be ignored. * @param bridgeMethodResolverFactory The bridge method resolver factory to be applied to any instrumentation * process. * @param classVisitorWrapperChain The class visitor wrapper chain to be applied to any instrumentation * process. * @param methodRegistry The currently valid method registry. * @param modifiers The modifiers to define for any instrumentation process. * @param typeAttributeAppender The type attribute appender to apply to any instrumentation process. * @param methodLookupEngineFactory The method lookup engine factory to apply to this configuration. * @param defaultFieldAttributeAppenderFactory The field attribute appender to apply as a default for any field * definition. * @param defaultMethodAttributeAppenderFactory The method attribute appender to apply as a default for any * method definition or instrumentation. * @param methodMatcher The method matcher representing the current method selection. * @param instrumentation The instrumentation that was defined for the current method * selection. * @param attributeAppenderFactory The method attribute appender factory that was defined for the * current method selection. */ protected MethodAnnotationTarget(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, List interfaceTypes, ElementMatcher ignoredMethods, BridgeMethodResolver.Factory bridgeMethodResolverFactory, ClassVisitorWrapper.Chain classVisitorWrapperChain, MethodRegistry methodRegistry, Definable modifiers, TypeAttributeAppender typeAttributeAppender, MethodLookupEngine.Factory methodLookupEngineFactory, FieldAttributeAppender.Factory defaultFieldAttributeAppenderFactory, MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory, ElementMatcher methodMatcher, Instrumentation instrumentation, MethodAttributeAppender.Factory attributeAppenderFactory) { super(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); this.methodMatcher = methodMatcher; this.instrumentation = instrumentation; this.attributeAppenderFactory = attributeAppenderFactory; } /** * Defines a given attribute appender factory to be applied for the currently selected methods. * * @param attributeAppenderFactory The method attribute appender factory to apply to the currently * selected methods. * @return A method annotation target that represents the current configuration with the additional * attribute appender factory applied to the current method selection. */ public MethodAnnotationTarget attribute(MethodAttributeAppender.Factory attributeAppenderFactory) { return new MethodAnnotationTarget(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, methodMatcher, instrumentation, new MethodAttributeAppender.Factory.Compound(this.attributeAppenderFactory, nonNull(attributeAppenderFactory))); } /** * Defines an method annotation for the currently selected methods. * * @param annotation The annotations to defined for the currently selected methods. * @return A method annotation target that represents the current configuration with the additional * annotations added to the currently selected methods. */ public MethodAnnotationTarget annotateMethod(Annotation... annotation) { return attribute(new MethodAttributeAppender.ForAnnotation(nonNull(annotation))); } /** * Defines an method annotation for a parameter of the currently selected methods. * * @param parameterIndex The index of the parameter for which the annotations should be applied * with the first parameter index by {@code 0}. * @param annotation The annotations to defined for the currently selected methods' parameters * ath the given index. * @return A method annotation target that represents the current configuration with the additional * annotations added to the currently selected methods' parameters at the given index. */ public MethodAnnotationTarget annotateParameter(int parameterIndex, Annotation... annotation) { return attribute(new MethodAttributeAppender.ForAnnotation(parameterIndex, nonNull(annotation))); } @Override protected ByteBuddy materialize() { return new ByteBuddy(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry.prepend(new MethodRegistry.LatentMethodMatcher.Simple(methodMatcher), instrumentation, attributeAppenderFactory), modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory ); } @Override public boolean equals(Object other) { if (this == other) return true; if (other == null || getClass() != other.getClass()) return false; if (!super.equals(other)) return false; MethodAnnotationTarget that = (MethodAnnotationTarget) other; return attributeAppenderFactory.equals(that.attributeAppenderFactory) && instrumentation.equals(that.instrumentation) && methodMatcher.equals(that.methodMatcher); } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + methodMatcher.hashCode(); result = 31 * result + instrumentation.hashCode(); result = 31 * result + attributeAppenderFactory.hashCode(); return result; } @Override public String toString() { return "ByteBuddy.MethodAnnotationTarget{" + "base=" + super.toString() + ", methodMatcher=" + methodMatcher + ", instrumentation=" + instrumentation + ", attributeAppenderFactory=" + attributeAppenderFactory + '}'; } } /** * An optional method interception that allows to intercept a method selection only if this is needed. */ public static class OptionalMethodInterception extends ByteBuddy implements MethodInterceptable { /** * The method matcher that defines the selected that is represented by this instance. */ protected final ElementMatcher methodMatcher; /** * Creates a new optional method interception. * * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param interfaceTypes The currently defined collection of interfaces to be implemented * by any dynamically created type. * @param ignoredMethods The methods to always be ignored. * @param bridgeMethodResolverFactory The bridge method resolver factory to be applied to any instrumentation * process. * @param classVisitorWrapperChain The class visitor wrapper chain to be applied to any instrumentation * process. * @param methodRegistry The currently valid method registry. * @param modifiers The modifiers to define for any instrumentation process. * @param typeAttributeAppender The type attribute appender to apply to any instrumentation process. * @param methodLookupEngineFactory The method lookup engine factory to apply to this configuration. * @param defaultFieldAttributeAppenderFactory The field attribute appender to apply as a default for any field * definition. * @param defaultMethodAttributeAppenderFactory The method attribute appender to apply as a default for any * method definition or instrumentation. * @param methodMatcher The method matcher representing the current method selection. */ protected OptionalMethodInterception(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, List interfaceTypes, ElementMatcher ignoredMethods, BridgeMethodResolver.Factory bridgeMethodResolverFactory, ClassVisitorWrapper.Chain classVisitorWrapperChain, MethodRegistry methodRegistry, Definable modifiers, TypeAttributeAppender typeAttributeAppender, MethodLookupEngine.Factory methodLookupEngineFactory, FieldAttributeAppender.Factory defaultFieldAttributeAppenderFactory, MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory, ElementMatcher methodMatcher) { super(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); this.methodMatcher = methodMatcher; } @Override public MethodAnnotationTarget intercept(Instrumentation instrumentation) { return new MatchedMethodInterception(methodMatcher).intercept(instrumentation); } @Override public MethodAnnotationTarget withoutCode() { return new MatchedMethodInterception(methodMatcher).withoutCode(); } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && super.equals(other) && methodMatcher.equals(((OptionalMethodInterception) other).methodMatcher); } @Override public int hashCode() { return 31 * methodMatcher.hashCode() + super.hashCode(); } @Override public String toString() { return "ByteBuddy.OptionalMethodInterception{" + "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", interfaceTypes=" + interfaceTypes + ", ignoredMethods=" + ignoredMethods + ", bridgeMethodResolverFactory=" + bridgeMethodResolverFactory + ", classVisitorWrapperChain=" + classVisitorWrapperChain + ", methodRegistry=" + methodRegistry + ", modifiers=" + modifiers + ", methodLookupEngineFactory=" + methodLookupEngineFactory + ", typeAttributeAppender=" + typeAttributeAppender + ", defaultFieldAttributeAppenderFactory=" + defaultFieldAttributeAppenderFactory + ", defaultMethodAttributeAppenderFactory=" + defaultMethodAttributeAppenderFactory + ", methodMatcher=" + methodMatcher + '}'; } } /** * A proxy implementation for extending Byte Buddy while allowing for enhancing a {@link com.ui4j.bytebuddy.ByteBuddy} * configuration. */ protected abstract static class Proxy extends ByteBuddy { /** * Defines a new proxy configuration for {@code ByteBuddy}. * * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param interfaceTypes The currently defined collection of interfaces to be * implemented by any dynamically created type. * @param ignoredMethods The methods to always be ignored. * @param bridgeMethodResolverFactory The bridge method resolver factory to be applied to any * instrumentation process. * @param classVisitorWrapperChain The class visitor wrapper chain to be applied to any * instrumentation process. * @param methodRegistry The currently valid method registry. * @param modifiers The modifiers to define for any instrumentation process. * @param typeAttributeAppender The type attribute appender to apply to any instrumentation * process. * @param methodLookupEngineFactory The method lookup engine factory to apply to this configuration. * @param defaultFieldAttributeAppenderFactory The field attribute appender to apply as a default for any * field definition. * @param defaultMethodAttributeAppenderFactory The method attribute appender to apply as a default for any * method definition or instrumentation. */ protected Proxy(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, List interfaceTypes, ElementMatcher ignoredMethods, BridgeMethodResolver.Factory bridgeMethodResolverFactory, ClassVisitorWrapper.Chain classVisitorWrapperChain, MethodRegistry methodRegistry, Definable modifiers, TypeAttributeAppender typeAttributeAppender, MethodLookupEngine.Factory methodLookupEngineFactory, FieldAttributeAppender.Factory defaultFieldAttributeAppenderFactory, MethodAttributeAppender.Factory defaultMethodAttributeAppenderFactory) { super(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory); } @Override public ClassFileVersion getClassFileVersion() { return materialize().getClassFileVersion(); } @Override public NamingStrategy.Unbound getNamingStrategy() { return materialize().getNamingStrategy(); } @Override public List getInterfaceTypes() { return materialize().getInterfaceTypes(); } @Override public ElementMatcher getIgnoredMethods() { return materialize().getIgnoredMethods(); } @Override public BridgeMethodResolver.Factory getBridgeMethodResolverFactory() { return materialize().getBridgeMethodResolverFactory(); } @Override public ClassVisitorWrapper.Chain getClassVisitorWrapperChain() { return materialize().getClassVisitorWrapperChain(); } @Override public MethodRegistry getMethodRegistry() { return materialize().getMethodRegistry(); } @Override public Definable getModifiers() { return materialize().getModifiers(); } @Override public MethodLookupEngine.Factory getMethodLookupEngineFactory() { return materialize().getMethodLookupEngineFactory(); } @Override public TypeAttributeAppender getTypeAttributeAppender() { return materialize().getTypeAttributeAppender(); } @Override public FieldAttributeAppender.Factory getDefaultFieldAttributeAppenderFactory() { return materialize().getDefaultFieldAttributeAppenderFactory(); } @Override public MethodAttributeAppender.Factory getDefaultMethodAttributeAppenderFactory() { return materialize().getDefaultMethodAttributeAppenderFactory(); } @Override public DynamicType.Builder subclass(Class superType) { return materialize().subclass(superType); } @Override public DynamicType.Builder subclass(Class superType, ConstructorStrategy constructorStrategy) { return materialize().subclass(superType, constructorStrategy); } @Override public DynamicType.Builder subclass(TypeDescription superType) { return materialize().subclass(superType); } @Override public DynamicType.Builder subclass(TypeDescription superType, ConstructorStrategy constructorStrategy) { return materialize().subclass(superType, constructorStrategy); } @Override public DynamicType.Builder redefine(Class levelType) { return materialize().redefine(levelType); } @Override public DynamicType.Builder redefine(Class levelType, ClassFileLocator classFileLocator) { return materialize().redefine(levelType, classFileLocator); } @Override public DynamicType.Builder redefine(TypeDescription levelType, ClassFileLocator classFileLocator) { return materialize().redefine(levelType, classFileLocator); } @Override public DynamicType.Builder rebase(Class levelType) { return materialize().rebase(levelType); } @Override public DynamicType.Builder rebase(Class levelType, ClassFileLocator classFileLocator) { return materialize().rebase(levelType, classFileLocator); } @Override public DynamicType.Builder rebase(Class levelType, ClassFileLocator classFileLocator, MethodRebaseResolver.MethodNameTransformer methodNameTransformer) { return materialize().rebase(levelType, classFileLocator, methodNameTransformer); } @Override public DynamicType.Builder rebase(TypeDescription levelType, ClassFileLocator classFileLocator) { return materialize().rebase(levelType, classFileLocator); } @Override public DynamicType.Builder rebase(TypeDescription levelType, ClassFileLocator classFileLocator, MethodRebaseResolver.MethodNameTransformer methodNameTransformer) { return super.rebase(levelType, classFileLocator, methodNameTransformer); } @Override public ByteBuddy withClassFileVersion(ClassFileVersion classFileVersion) { return materialize().withClassFileVersion(classFileVersion); } @Override public ByteBuddy withNamingStrategy(NamingStrategy.Unbound namingStrategy) { return materialize().withNamingStrategy(namingStrategy); } @Override public ByteBuddy withNamingStrategy(NamingStrategy namingStrategy) { return materialize().withNamingStrategy(namingStrategy); } @Override public ByteBuddy withModifiers(ModifierContributor.ForType... modifierContributor) { return materialize().withModifiers(modifierContributor); } @Override public ByteBuddy withAttribute(TypeAttributeAppender typeAttributeAppender) { return materialize().withAttribute(typeAttributeAppender); } @Override public ByteBuddy withTypeAnnotation(Annotation... annotation) { return materialize().withTypeAnnotation(annotation); } @Override public OptionalMethodInterception withImplementing(Class... type) { return materialize().withImplementing(type); } @Override public OptionalMethodInterception withImplementing(TypeDescription... type) { return materialize().withImplementing(type); } @Override public ByteBuddy withIgnoredMethods(ElementMatcher ignoredMethods) { return materialize().withIgnoredMethods(ignoredMethods); } @Override public ByteBuddy withBridgeMethodResolver(BridgeMethodResolver.Factory bridgeMethodResolverFactory) { return materialize().withBridgeMethodResolver(bridgeMethodResolverFactory); } @Override public ByteBuddy withClassVisitor(ClassVisitorWrapper classVisitorWrapper) { return materialize().withClassVisitor(classVisitorWrapper); } @Override public ByteBuddy withMethodLookupEngine(MethodLookupEngine.Factory methodLookupEngineFactory) { return materialize().withMethodLookupEngine(methodLookupEngineFactory); } @Override public ByteBuddy withDefaultFieldAttributeAppender(FieldAttributeAppender.Factory attributeAppenderFactory) { return materialize().withDefaultFieldAttributeAppender(attributeAppenderFactory); } @Override public ByteBuddy withDefaultMethodAttributeAppender(MethodAttributeAppender.Factory attributeAppenderFactory) { return materialize().withDefaultMethodAttributeAppender(attributeAppenderFactory); } @Override public MatchedMethodInterception invokable(ElementMatcher methodMatcher) { return materialize().invokable(methodMatcher); } @Override public MatchedMethodInterception method(ElementMatcher methodMatcher) { return materialize().method(methodMatcher); } @Override public MatchedMethodInterception constructor(ElementMatcher methodMatcher) { return materialize().constructor(methodMatcher); } /** * Materializes the current extended configuration. * * @return The materialized Byte Buddy configuration. */ protected abstract ByteBuddy materialize(); } /** * A matched method interception for a non-optional method definition. */ public class MatchedMethodInterception implements MethodInterceptable { /** * A method matcher that represents the current method selection. */ protected final ElementMatcher methodMatcher; /** * Creates a new matched method interception. * * @param methodMatcher The method matcher representing the current method selection. */ protected MatchedMethodInterception(ElementMatcher methodMatcher) { this.methodMatcher = methodMatcher; } @Override public MethodAnnotationTarget intercept(Instrumentation instrumentation) { return new MethodAnnotationTarget(classFileVersion, namingStrategy, interfaceTypes, ignoredMethods, bridgeMethodResolverFactory, classVisitorWrapperChain, methodRegistry, modifiers, typeAttributeAppender, methodLookupEngineFactory, defaultFieldAttributeAppenderFactory, defaultMethodAttributeAppenderFactory, methodMatcher, nonNull(instrumentation), MethodAttributeAppender.NoOp.INSTANCE); } @Override public MethodAnnotationTarget withoutCode() { return intercept(Instrumentation.ForAbstractMethod.INSTANCE); } /** * Returns the outer class instance of this instance. * * @return The outer class instance. */ private ByteBuddy getByteBuddy() { return ByteBuddy.this; } @Override public boolean equals(Object other) { return this == other || !(other == null || getClass() != other.getClass()) && ByteBuddy.this.equals(((MatchedMethodInterception) other).getByteBuddy()) && methodMatcher.equals(((MatchedMethodInterception) other).methodMatcher); } @Override public int hashCode() { return 31 * methodMatcher.hashCode() + ByteBuddy.this.hashCode(); } @Override public String toString() { return "ByteBuddy.MatchedMethodInterception{" + "methodMatcher=" + methodMatcher + "byteBuddy=" + ByteBuddy.this.toString() + '}'; } } }