diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/ByteBuddy.java b/byte-buddy-dep/src/main/java/net/bytebuddy/ByteBuddy.java index c73aabc6422..9ed6aca6afc 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/ByteBuddy.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/ByteBuddy.java @@ -90,6 +90,11 @@ public class ByteBuddy { */ protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy; + /** + * The currently defined implementation context factory. + */ + protected final Implementation.Context.Factory implementationContextFactory; + /** * A list of interface types to be implemented by any class that is implemented by the current configuration. */ @@ -154,6 +159,7 @@ public ByteBuddy(ClassFileVersion classFileVersion) { this(nonNull(classFileVersion), new NamingStrategy.Unbound.Default(BYTE_BUDDY_DEFAULT_PREFIX), new AuxiliaryType.NamingStrategy.SuffixingRandom(BYTE_BUDDY_DEFAULT_SUFFIX), + Implementation.Context.Default.Factory.INSTANCE, new TypeList.Empty(), isSynthetic().or(isDefaultFinalizer()), new ClassVisitorWrapper.Chain(), @@ -171,6 +177,7 @@ public ByteBuddy(ClassFileVersion classFileVersion) { * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param auxiliaryTypeNamingStrategy The currently defined naming strategy for auxiliary types. + * @param implementationContextFactory The currently defined implementation context factory. * @param interfaceTypes The currently defined collection of interfaces to be implemented * by any dynamically created type. * @param ignoredMethods The methods to always be ignored. @@ -189,6 +196,7 @@ public ByteBuddy(ClassFileVersion classFileVersion) { protected ByteBuddy(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, List interfaceTypes, ElementMatcher ignoredMethods, ClassVisitorWrapper.Chain classVisitorWrapperChain, @@ -201,6 +209,7 @@ protected ByteBuddy(ClassFileVersion classFileVersion, this.classFileVersion = classFileVersion; this.namingStrategy = namingStrategy; this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy; + this.implementationContextFactory = implementationContextFactory; this.interfaceTypes = interfaceTypes; this.ignoredMethods = ignoredMethods; this.classVisitorWrapperChain = classVisitorWrapperChain; @@ -212,118 +221,6 @@ protected ByteBuddy(ClassFileVersion classFileVersion, 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 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 graph compiler that is used. - * - * @return The method graph compiler that is used. - */ - public MethodGraph.Compiler getMethodGraphCompiler() { - return methodGraphCompiler; - } - - /** - * 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 implementations that are applied by this configuration. - * - * @return The default field attribute appender factory which is applied to any field that is defined - * for implementations 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 implementations 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 implementations that are applied by this configuration. - */ - public MethodAttributeAppender.Factory getDefaultMethodAttributeAppenderFactory() { - return defaultMethodAttributeAppenderFactory; - } - - /** - * Returns the used naming strategy for auxiliary types. - * - * @return The used naming strategy for auxiliary types. - */ - public AuxiliaryType.NamingStrategy getAuxiliaryTypeNamingStrategy() { - return auxiliaryTypeNamingStrategy; - } - /** * Creates a dynamic type builder that creates a subclass of a given loaded type where the subclass * is created by the {@link net.bytebuddy.dynamic.scaffold.subclass.ConstructorStrategy.Default#IMITATE_SUPER_TYPE} @@ -380,6 +277,7 @@ public DynamicType.Builder subclass(TypeDescription superType, Constructo return new SubclassDynamicTypeBuilder(classFileVersion, nonNull(namingStrategy.subclass(superType)), auxiliaryTypeNamingStrategy, + implementationContextFactory, actualSuperType, interfaceTypes, modifiers.resolve(superType.getModifiers() & ~TypeManifestation.ANNOTATION.getMask()), @@ -460,6 +358,7 @@ public DynamicType.Builder makeInterface(Collection(classFileVersion, namingStrategy.create(), auxiliaryTypeNamingStrategy, + implementationContextFactory, TypeDescription.OBJECT, join(interfaceTypes, toList(nonNull(typeDescriptions))), modifiers.resolve(Opcodes.ACC_PUBLIC) | TypeManifestation.INTERFACE.getMask(), @@ -485,6 +384,7 @@ public DynamicType.Builder makePackage(String name) { return new SubclassDynamicTypeBuilder>(classFileVersion, new NamingStrategy.Fixed(isValidIdentifier(name) + "." + PackageDescription.PACKAGE_CLASS_NAME), auxiliaryTypeNamingStrategy, + implementationContextFactory, TypeDescription.OBJECT, new TypeList.Empty(), PackageDescription.PACKAGE_MODIFIERS, @@ -533,6 +433,7 @@ public DynamicType.Builder makeAnnotation() { return (DynamicType.Builder) (Object) new SubclassDynamicTypeBuilder(classFileVersion, namingStrategy.create(), auxiliaryTypeNamingStrategy, + implementationContextFactory, TypeDescription.OBJECT, Collections.singletonList(new TypeDescription.ForLoadedType(Annotation.class)), modifiers.resolve(Opcodes.ACC_PUBLIC) | TypeManifestation.ANNOTATION.getMask(), @@ -571,6 +472,7 @@ public DynamicType.Builder> makeEnumeration(Collection>(classFileVersion, nonNull(namingStrategy.subclass(TypeDescription.ENUM)), auxiliaryTypeNamingStrategy, + implementationContextFactory, TypeDescription.ENUM, interfaceTypes, Visibility.PUBLIC.getMask() | TypeManifestation.FINAL.getMask() | EnumerationState.ENUMERATION.getMask(), @@ -661,6 +563,7 @@ public DynamicType.Builder redefine(TypeDescription levelType, ClassFileL return new RedefinitionDynamicTypeBuilder(classFileVersion, nonNull(namingStrategy.redefine(levelType)), auxiliaryTypeNamingStrategy, + implementationContextFactory, nonNull(levelType), interfaceTypes, modifiers.resolve(levelType.getModifiers()), @@ -788,6 +691,7 @@ public DynamicType.Builder rebase(TypeDescription levelType, return new RebaseDynamicTypeBuilder(classFileVersion, nonNull(namingStrategy.rebase(isDefineable(levelType))), auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, interfaceTypes, modifiers.resolve(levelType.getModifiers()), @@ -813,6 +717,7 @@ public ByteBuddy withClassFileVersion(ClassFileVersion classFileVersion) { return new ByteBuddy(nonNull(classFileVersion), namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -834,6 +739,7 @@ public ByteBuddy withNamingStrategy(NamingStrategy.Unbound namingStrategy) { return new ByteBuddy(classFileVersion, nonNull(namingStrategy), auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -865,6 +771,29 @@ public ByteBuddy withNamingStrategy(AuxiliaryType.NamingStrategy auxiliaryTypeNa return new ByteBuddy(classFileVersion, namingStrategy, nonNull(auxiliaryTypeNamingStrategy), + implementationContextFactory, + interfaceTypes, + ignoredMethods, + classVisitorWrapperChain, + methodRegistry, + modifiers, + typeAttributeAppender, + methodGraphCompiler, + defaultFieldAttributeAppenderFactory, + defaultMethodAttributeAppenderFactory); + } + + /** + * Defines a factory for creating an {@link net.bytebuddy.implementation.Implementation.Context}. + * + * @param implementationContextFactory The factory to use. + * @return This configuration with the defined implementation context factory. + */ + public ByteBuddy withContext(Implementation.Context.Factory implementationContextFactory) { + return new ByteBuddy(classFileVersion, + namingStrategy, + auxiliaryTypeNamingStrategy, + nonNull(implementationContextFactory), interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -887,6 +816,7 @@ public ByteBuddy withModifiers(ModifierContributor.ForType... modifierContributo return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -909,6 +839,7 @@ public ByteBuddy withAttribute(TypeAttributeAppender typeAttributeAppender) { return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -968,6 +899,7 @@ public ByteBuddy withTypeAnnotation(Collection return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1023,6 +955,7 @@ public OptionalMethodInterception withImplementing(Collection ig return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, nonNull(ignoredMethods), classVisitorWrapperChain, @@ -1072,6 +1006,7 @@ public ByteBuddy withClassVisitor(ClassVisitorWrapper classVisitorWrapper) { return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain.append(nonNull(classVisitorWrapper)), @@ -1093,6 +1028,7 @@ public ByteBuddy withMethodGraphCompiler(MethodGraph.Compiler methodGraphCompile return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1117,6 +1053,7 @@ public ByteBuddy withDefaultFieldAttributeAppender(FieldAttributeAppender.Factor return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1141,6 +1078,7 @@ public ByteBuddy withDefaultMethodAttributeAppender(MethodAttributeAppender.Fact return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1210,6 +1148,7 @@ public boolean equals(Object other) { && modifiers.equals(byteBuddy.modifiers) && namingStrategy.equals(byteBuddy.namingStrategy) && auxiliaryTypeNamingStrategy.equals(byteBuddy.auxiliaryTypeNamingStrategy) + && implementationContextFactory.equals(byteBuddy.implementationContextFactory) && typeAttributeAppender.equals(byteBuddy.typeAttributeAppender); } @@ -1218,6 +1157,7 @@ public int hashCode() { int result = classFileVersion.hashCode(); result = 31 * result + namingStrategy.hashCode(); result = 31 * result + auxiliaryTypeNamingStrategy.hashCode(); + result = 31 * result + implementationContextFactory.hashCode(); result = 31 * result + interfaceTypes.hashCode(); result = 31 * result + ignoredMethods.hashCode(); result = 31 * result + classVisitorWrapperChain.hashCode(); @@ -1236,6 +1176,7 @@ public String toString() { "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", interfaceTypes=" + interfaceTypes + ", ignoredMethods=" + ignoredMethods + ", classVisitorWrapperChain=" + classVisitorWrapperChain + @@ -1431,6 +1372,7 @@ public static class MethodAnnotationTarget extends Proxy { * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param auxiliaryTypeNamingStrategy The currently defined naming strategy for auxiliary types. + * @param implementationContextFactory The currently defined implementation context factory. * @param interfaceTypes The currently defined collection of interfaces to be implemented * by any dynamically created type. * @param ignoredMethods The methods to always be ignored. @@ -1453,6 +1395,7 @@ public static class MethodAnnotationTarget extends Proxy { protected MethodAnnotationTarget(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, List interfaceTypes, ElementMatcher ignoredMethods, ClassVisitorWrapper.Chain classVisitorWrapperChain, @@ -1469,6 +1412,7 @@ protected MethodAnnotationTarget(ClassFileVersion classFileVersion, super(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1496,6 +1440,7 @@ public MethodAnnotationTarget attribute(MethodAttributeAppender.Factory attribut return new MethodAnnotationTarget(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1593,6 +1538,7 @@ protected ByteBuddy materialize() { return new ByteBuddy(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1636,6 +1582,7 @@ public String toString() { "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", interfaceTypes=" + interfaceTypes + ", ignoredMethods=" + ignoredMethods + ", classVisitorWrapperChain=" + classVisitorWrapperChain + @@ -1669,6 +1616,7 @@ public static class OptionalMethodInterception extends ByteBuddy implements Meth * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param auxiliaryTypeNamingStrategy The currently defined naming strategy for auxiliary types. + * @param implementationContextFactory The currently defined implementation context factory. * @param interfaceTypes The currently defined collection of interfaces to be implemented * by any dynamically created type. * @param ignoredMethods The methods to always be ignored. @@ -1688,6 +1636,7 @@ public static class OptionalMethodInterception extends ByteBuddy implements Meth protected OptionalMethodInterception(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, List interfaceTypes, ElementMatcher ignoredMethods, ClassVisitorWrapper.Chain classVisitorWrapperChain, @@ -1701,6 +1650,7 @@ protected OptionalMethodInterception(ClassFileVersion classFileVersion, super(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1750,6 +1700,7 @@ public String toString() { "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", interfaceTypes=" + interfaceTypes + ", ignoredMethods=" + ignoredMethods + ", classVisitorWrapperChain=" + classVisitorWrapperChain + @@ -1776,6 +1727,7 @@ protected abstract static class Proxy extends ByteBuddy { * @param classFileVersion The currently defined class file version. * @param namingStrategy The currently defined naming strategy. * @param auxiliaryTypeNamingStrategy The currently defined naming strategy for auxiliary types. + * @param implementationContextFactory The currently defined implementation context factory. * @param interfaceTypes The currently defined collection of interfaces to be * implemented by any dynamically created type. * @param ignoredMethods The methods to always be ignored. @@ -1795,6 +1747,7 @@ protected abstract static class Proxy extends ByteBuddy { protected Proxy(ClassFileVersion classFileVersion, NamingStrategy.Unbound namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, List interfaceTypes, ElementMatcher ignoredMethods, ClassVisitorWrapper.Chain classVisitorWrapperChain, @@ -1807,6 +1760,7 @@ protected Proxy(ClassFileVersion classFileVersion, super(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -1818,66 +1772,6 @@ protected Proxy(ClassFileVersion classFileVersion, 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 ClassVisitorWrapper.Chain getClassVisitorWrapperChain() { - return materialize().getClassVisitorWrapperChain(); - } - - @Override - public MethodRegistry getMethodRegistry() { - return materialize().getMethodRegistry(); - } - - @Override - public Definable getModifiers() { - return materialize().getModifiers(); - } - - @Override - public MethodGraph.Compiler getMethodGraphCompiler() { - return materialize().getMethodGraphCompiler(); - } - - @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 AuxiliaryType.NamingStrategy getAuxiliaryTypeNamingStrategy() { - return materialize().getAuxiliaryTypeNamingStrategy(); - } - @Override public DynamicType.Builder subclass(Class superType) { return materialize().subclass(superType); @@ -1967,6 +1861,11 @@ public ByteBuddy withNamingStrategy(AuxiliaryType.NamingStrategy auxiliaryTypeNa return materialize().withNamingStrategy(auxiliaryTypeNamingStrategy); } + @Override + public ByteBuddy withContext(Implementation.Context.Factory implementationContextFactory) { + return materialize().withContext(implementationContextFactory); + } + @Override public ByteBuddy withModifiers(ModifierContributor.ForType... modifierContributor) { return materialize().withModifiers(modifierContributor); @@ -2356,6 +2255,7 @@ public MethodAnnotationTarget intercept(Implementation implementation) { return new MethodAnnotationTarget(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -2376,6 +2276,7 @@ public MethodAnnotationTarget withoutCode() { return new MethodAnnotationTarget(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -2401,6 +2302,7 @@ public MethodAnnotationTarget withDefaultValue(Object value) { return new MethodAnnotationTarget(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, interfaceTypes, ignoredMethods, classVisitorWrapperChain, @@ -2441,7 +2343,7 @@ public int hashCode() { public String toString() { return "ByteBuddy.MatchedMethodInterception{" + "methodMatcher=" + methodMatcher + - "byteBuddy=" + ByteBuddy.this.toString() + + ", byteBuddy=" + ByteBuddy.this.toString() + '}'; } } diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java b/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java index c008b00ec9a..c4f206c5a49 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/agent/builder/AgentBuilder.java @@ -130,6 +130,14 @@ public interface AgentBuilder { */ AgentBuilder withBinaryLocator(BinaryLocator binaryLocator); + /** + * efines the use of the given definition handler that determines if a type should be rebased or redefined. + * + * @param definitionHandler The definition handler to use. + * @return A new instance of this agent builder which uses the given definition handler. + */ + AgentBuilder withDefinitionHandler(DefinitionHandler definitionHandler); + /** * Enables the use of the given native method prefix for instrumented methods. Note that this prefix is also * applied when preserving non-native methods. The use of this prefix is also registered when installing the @@ -327,6 +335,63 @@ public String toString() { } } + /** + * A definition handler is responsible for creating a type builder for a type that is being instrumented. + */ + interface DefinitionHandler { + + /** + * Creates a type builder for a given type. + * + * @param typeDescription The type being instrumented. + * @param byteBuddy The Byte Buddy configuration. + * @param classFileLocator The class file locator to use. + * @param methodNameTransformer The method name transformer to use. + * @return A type builder for the given arguments. + */ + DynamicType.Builder builder(TypeDescription typeDescription, + ByteBuddy byteBuddy, + ClassFileLocator classFileLocator, + MethodRebaseResolver.MethodNameTransformer methodNameTransformer); + + /** + * A default implementation of a definition handler. + */ + enum Default implements DefinitionHandler { + + /** + * A definition handler that performs a rebasing for all types. + */ + REBASE { + @Override + public DynamicType.Builder builder(TypeDescription typeDescription, + ByteBuddy byteBuddy, + ClassFileLocator classFileLocator, + MethodRebaseResolver.MethodNameTransformer methodNameTransformer) { + return byteBuddy.rebase(typeDescription, classFileLocator, methodNameTransformer); + } + }, + + /** + * A definition handler that performas a redefition for all types. + */ + REDEFINE { + @Override + public DynamicType.Builder builder(TypeDescription typeDescription, + ByteBuddy byteBuddy, + ClassFileLocator classFileLocator, + MethodRebaseResolver.MethodNameTransformer methodNameTransformer) { + return byteBuddy.redefine(typeDescription, classFileLocator); + } + }; + + @Override + public String toString() { + return "AgentBuilder.DefinitionHandler.Default." + name(); + } + } + } + /** * A transformer allows to apply modifications to a {@link net.bytebuddy.dynamic.DynamicType}. Such a modification * is then applied to any instrumented type that was matched by the preceding matcher. @@ -765,6 +830,11 @@ class Default implements AgentBuilder { */ private final BinaryLocator binaryLocator; + /** + * The definition handler to use. + */ + private final DefinitionHandler definitionHandler; + /** * The listener to notify on transformations. */ @@ -820,6 +890,7 @@ public Default() { public Default(ByteBuddy byteBuddy) { this(nonNull(byteBuddy), BinaryLocator.Default.INSTANCE, + DefinitionHandler.Default.REBASE, Listener.NoOp.INSTANCE, NO_NATIVE_PREFIX, AccessController.getContext(), @@ -834,6 +905,7 @@ public Default(ByteBuddy byteBuddy) { * * @param byteBuddy The Byte Buddy instance to be used. * @param binaryLocator The binary locator to use. + * @param definitionHandler The definition handler to use. * @param listener The listener to notify on transformations. * @param nativeMethodPrefix The native method prefix to use which might also represent * {@link net.bytebuddy.agent.builder.AgentBuilder.Default#NO_NATIVE_PREFIX} @@ -851,6 +923,7 @@ public Default(ByteBuddy byteBuddy) { */ protected Default(ByteBuddy byteBuddy, BinaryLocator binaryLocator, + DefinitionHandler definitionHandler, Listener listener, String nativeMethodPrefix, AccessControlContext accessControlContext, @@ -860,6 +933,7 @@ protected Default(ByteBuddy byteBuddy, List transformations) { this.byteBuddy = byteBuddy; this.binaryLocator = binaryLocator; + this.definitionHandler = definitionHandler; this.listener = listener; this.nativeMethodPrefix = nativeMethodPrefix; this.accessControlContext = accessControlContext; @@ -888,6 +962,7 @@ public Identified rebase(ElementMatcher typeMatcher, El public AgentBuilder withByteBuddy(ByteBuddy byteBuddy) { return new Default(nonNull(byteBuddy), binaryLocator, + definitionHandler, listener, nativeMethodPrefix, accessControlContext, @@ -901,6 +976,7 @@ public AgentBuilder withByteBuddy(ByteBuddy byteBuddy) { public AgentBuilder withListener(Listener listener) { return new Default(byteBuddy, binaryLocator, + definitionHandler, new Listener.Compound(this.listener, nonNull(listener)), nativeMethodPrefix, accessControlContext, @@ -910,10 +986,25 @@ public AgentBuilder withListener(Listener listener) { transformations); } + @Override + public AgentBuilder withDefinitionHandler(DefinitionHandler definitionHandler) { + return new Default(byteBuddy, + binaryLocator, + nonNull(definitionHandler), + listener, + nativeMethodPrefix, + accessControlContext, + disableSelfInitialization, + retransformation, + bootstrapInjectionStrategy, + transformations); + } + @Override public AgentBuilder withBinaryLocator(BinaryLocator binaryLocator) { return new Default(byteBuddy, nonNull(binaryLocator), + definitionHandler, listener, nativeMethodPrefix, accessControlContext, @@ -930,6 +1021,7 @@ public AgentBuilder withNativeMethodPrefix(String prefix) { } return new Default(byteBuddy, binaryLocator, + definitionHandler, listener, prefix, accessControlContext, @@ -943,6 +1035,7 @@ public AgentBuilder withNativeMethodPrefix(String prefix) { public AgentBuilder withAccessControlContext(AccessControlContext accessControlContext) { return new Default(byteBuddy, binaryLocator, + definitionHandler, listener, nativeMethodPrefix, accessControlContext, @@ -956,6 +1049,7 @@ public AgentBuilder withAccessControlContext(AccessControlContext accessControlC public AgentBuilder allowRetransformation() { return new Default(byteBuddy, binaryLocator, + definitionHandler, listener, nativeMethodPrefix, accessControlContext, @@ -969,6 +1063,7 @@ public AgentBuilder allowRetransformation() { public AgentBuilder disableSelfInitialization() { return new Default(byteBuddy, binaryLocator, + definitionHandler, listener, nativeMethodPrefix, accessControlContext, @@ -982,6 +1077,7 @@ public AgentBuilder disableSelfInitialization() { public AgentBuilder enableBootstrapInjection(File folder, Instrumentation instrumentation) { return new Default(byteBuddy, binaryLocator, + definitionHandler, listener, nativeMethodPrefix, accessControlContext, @@ -1015,11 +1111,11 @@ public ClassFileTransformer installOn(Instrumentation instrumentation) { } } if (retransformedTypes.size() > 0) { - try { - instrumentation.retransformClasses(retransformedTypes.toArray(new Class[retransformedTypes.size()])); - } catch (UnmodifiableClassException exception) { - throw new IllegalStateException("Cannot retransform classes: " + retransformedTypes, exception); - } + try { + instrumentation.retransformClasses(retransformedTypes.toArray(new Class[retransformedTypes.size()])); + } catch (UnmodifiableClassException exception) { + throw new IllegalStateException("Cannot retransform classes: " + retransformedTypes, exception); + } } } return classFileTransformer; @@ -1048,6 +1144,7 @@ public boolean equals(Object other) { && byteBuddy.equals(aDefault.byteBuddy) && listener.equals(aDefault.listener) && nativeMethodPrefix.equals(aDefault.nativeMethodPrefix) + && definitionHandler.equals(aDefault.definitionHandler) && accessControlContext.equals(aDefault.accessControlContext) && disableSelfInitialization == aDefault.disableSelfInitialization && retransformation == aDefault.retransformation @@ -1061,6 +1158,7 @@ public int hashCode() { int result = byteBuddy.hashCode(); result = 31 * result + binaryLocator.hashCode(); result = 31 * result + listener.hashCode(); + result = 31 * result + definitionHandler.hashCode(); result = 31 * result + nativeMethodPrefix.hashCode(); result = 31 * result + accessControlContext.hashCode(); result = 31 * result + (disableSelfInitialization ? 1 : 0); @@ -1075,6 +1173,7 @@ public String toString() { return "AgentBuilder.Default{" + "byteBuddy=" + byteBuddy + ", binaryLocator=" + binaryLocator + + ", definitionHandler=" + definitionHandler + ", listener=" + listener + ", nativeMethodPrefix=" + nativeMethodPrefix + ", accessControlContext=" + accessControlContext + @@ -1636,7 +1735,7 @@ public byte[] transform(ClassLoader classLoader, for (Transformation transformation : transformations) { if (transformation.matches(typeDescription, classLoader, classBeingRedefined, protectionDomain)) { DynamicType.Unloaded dynamicType = initializationStrategy.apply( - transformation.transform(byteBuddy.rebase(typeDescription, + transformation.transform(definitionHandler.builder(typeDescription, byteBuddy, initialized.getClassFileLocator(), methodNameTransformer), typeDescription)).make(); Map loadedTypeInitializers = dynamicType.getLoadedTypeInitializers(); @@ -1732,6 +1831,11 @@ public AgentBuilder withListener(Listener listener) { return materialize().withListener(listener); } + @Override + public AgentBuilder withDefinitionHandler(DefinitionHandler definitionHandler) { + return materialize().withDefinitionHandler(definitionHandler); + } + @Override public AgentBuilder withBinaryLocator(BinaryLocator binaryLocator) { return materialize().withBinaryLocator(binaryLocator); @@ -1785,6 +1889,7 @@ public ClassFileTransformer installOnByteBuddyAgent() { protected AgentBuilder materialize() { return new Default(byteBuddy, binaryLocator, + definitionHandler, listener, nativeMethodPrefix, accessControlContext, diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java index a26ff83a00f..c7c43e32fc0 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/DynamicType.java @@ -251,6 +251,14 @@ interface Builder { */ Builder name(AuxiliaryType.NamingStrategy namingStrategy); + /** + * Defines a factory for creating an implementation context. + * + * @param implementationContextFactory The implementation context factory to use. + * @return This builder where the implementation context factory was set to be used. + */ + Builder context(Implementation.Context.Factory implementationContextFactory); + /** * Defines modifiers for the created dynamic type. * @@ -1188,6 +1196,11 @@ abstract class AbstractBase implements Builder { */ protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy; + /** + * The currently defined implementation context factory. + */ + protected final Implementation.Context.Factory implementationContextFactory; + /** * The target type description that is specified for this builder. */ @@ -1261,6 +1274,7 @@ abstract class AbstractBase implements Builder { * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy for naming auxiliary types of the dynamic type. + * @param implementationContextFactory The currently defined implementation context factory. * @param targetType A description of the type that the dynamic type should represent. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -1282,6 +1296,7 @@ abstract class AbstractBase implements Builder { protected AbstractBase(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription targetType, List interfaceTypes, int modifiers, @@ -1298,6 +1313,7 @@ protected AbstractBase(ClassFileVersion classFileVersion, this.classFileVersion = classFileVersion; this.namingStrategy = namingStrategy; this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy; + this.implementationContextFactory = implementationContextFactory; this.targetType = targetType; this.interfaceTypes = interfaceTypes; this.modifiers = modifiers; @@ -1334,9 +1350,7 @@ public OptionalMatchedMethodInterception implement(Collection defineField(String name, - Class fieldType, - ModifierContributor.ForField... modifier) { + public FieldValueTarget defineField(String name, Class fieldType, ModifierContributor.ForField... modifier) { return defineField(name, new TypeDescription.ForLoadedType(fieldType), modifier); } @@ -1362,6 +1376,7 @@ public Builder classFileVersion(ClassFileVersion classFileVersion) { return materialize(nonNull(classFileVersion), namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1382,6 +1397,7 @@ public Builder name(String name) { return materialize(classFileVersion, new NamingStrategy.Fixed(isValidTypeName(name)), auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1402,6 +1418,7 @@ public Builder name(NamingStrategy namingStrategy) { return materialize(classFileVersion, nonNull(namingStrategy), auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1422,6 +1439,28 @@ public Builder name(AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy) return materialize(classFileVersion, namingStrategy, nonNull(auxiliaryTypeNamingStrategy), + implementationContextFactory, + targetType, + interfaceTypes, + modifiers, + attributeAppender, + ignoredMethods, + classVisitorWrapperChain, + fieldRegistry, + methodRegistry, + methodGraphCompiler, + defaultFieldAttributeAppenderFactory, + defaultMethodAttributeAppenderFactory, + fieldTokens, + methodTokens); + } + + @Override + public Builder context(Implementation.Context.Factory implementationContextFactory) { + return materialize(classFileVersion, + namingStrategy, + auxiliaryTypeNamingStrategy, + nonNull(implementationContextFactory), targetType, interfaceTypes, modifiers, @@ -1442,6 +1481,7 @@ public Builder modifiers(ModifierContributor.ForType... modifier) { return materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, resolveModifierContributors(TYPE_MODIFIER_MASK, nonNull(modifier)), @@ -1462,6 +1502,7 @@ public Builder modifiers(int modifiers) { return materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1482,6 +1523,7 @@ public Builder ignoreMethods(ElementMatcher ignore return materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1502,6 +1544,7 @@ public Builder attribute(TypeAttributeAppender attributeAppender) { return materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1543,6 +1586,7 @@ public Builder classVisitor(ClassVisitorWrapper classVisitorWrapper) { return materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1563,6 +1607,7 @@ public Builder methodGraphCompiler(MethodGraph.Compiler methodGraphCompiler) return materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -1743,6 +1788,7 @@ public MatchedMethodInterception invokable(LatentMethodMatcher methodMatcher) * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy for naming the auxiliary type of the dynamic type. + * @param implementationContextFactory The currently defined implementation context factory. * @param targetType A description of the type that the dynamic type should represent. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -1765,6 +1811,7 @@ public MatchedMethodInterception invokable(LatentMethodMatcher methodMatcher) protected abstract Builder materialize(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription targetType, List interfaceTypes, int modifiers, @@ -1801,6 +1848,7 @@ public boolean equals(Object other) { && methodRegistry.equals(that.methodRegistry) && methodTokens.equals(that.methodTokens) && namingStrategy.equals(that.namingStrategy) + && implementationContextFactory.equals(that.implementationContextFactory) && auxiliaryTypeNamingStrategy.equals(that.auxiliaryTypeNamingStrategy); } @@ -1809,6 +1857,7 @@ public int hashCode() { int result = classFileVersion.hashCode(); result = 31 * result + namingStrategy.hashCode(); result = 31 * result + auxiliaryTypeNamingStrategy.hashCode(); + result = 31 * result + implementationContextFactory.hashCode(); result = 31 * result + targetType.hashCode(); result = 31 * result + interfaceTypes.hashCode(); result = 31 * result + modifiers; @@ -1874,6 +1923,11 @@ public Builder name(AuxiliaryType.NamingStrategy namingStrategy) { return materialize().name(namingStrategy); } + @Override + public Builder context(Implementation.Context.Factory implementationContextFactory) { + return materialize().context(implementationContextFactory); + } + @Override public Builder modifiers(ModifierContributor.ForType... modifier) { return materialize().modifiers(modifier); @@ -2131,6 +2185,7 @@ protected DynamicType.Builder materialize() { return AbstractBase.this.materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -2579,6 +2634,7 @@ protected DynamicType.Builder materialize() { return AbstractBase.this.materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -2757,6 +2813,7 @@ protected DynamicType.Builder materialize() { return AbstractBase.this.materialize(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, joinUniqueRaw(interfaceTypes, additionalInterfaceTypes), modifiers, diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java index 35dc4b82361..056a6f52b6c 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/TypeWriter.java @@ -1279,6 +1279,11 @@ abstract class Default implements TypeWriter { */ protected final AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy; + /** + * The implementation context factory to use. + */ + protected final Implementation.Context.Factory implementationContextFactory; + /** * A class visitor wrapper to apply during instrumentation. */ @@ -1307,17 +1312,18 @@ abstract class Default implements TypeWriter { /** * Creates a new default type writer. * - * @param instrumentedType The instrumented type that is to be written. - * @param loadedTypeInitializer The loaded type initializer of the instrumented type. - * @param typeInitializer The type initializer of the instrumented type. - * @param explicitAuxiliaryTypes A list of explicit auxiliary types that are to be added to the created dynamic type. - * @param classFileVersion The class file version of the written type. - * @param auxiliaryTypeNamingStrategy A naming strategy that is used for naming auxiliary types. - * @param classVisitorWrapper A class visitor wrapper to apply during instrumentation. - * @param attributeAppender The type attribute appender to apply. - * @param fieldPool The field pool to be used for instrumenting fields. - * @param methodPool The method pool to be used for instrumenting methods. - * @param instrumentedMethods A list of all instrumented methods. + * @param instrumentedType The instrumented type that is to be written. + * @param loadedTypeInitializer The loaded type initializer of the instrumented type. + * @param typeInitializer The type initializer of the instrumented type. + * @param explicitAuxiliaryTypes A list of explicit auxiliary types that are to be added to the created dynamic type. + * @param classFileVersion The class file version of the written type. + * @param auxiliaryTypeNamingStrategy A naming strategy that is used for naming auxiliary types. + * @param implementationContextFactory The implementation context factory to use. + * @param classVisitorWrapper A class visitor wrapper to apply during instrumentation. + * @param attributeAppender The type attribute appender to apply. + * @param fieldPool The field pool to be used for instrumenting fields. + * @param methodPool The method pool to be used for instrumenting methods. + * @param instrumentedMethods A list of all instrumented methods. */ protected Default(TypeDescription instrumentedType, LoadedTypeInitializer loadedTypeInitializer, @@ -1325,6 +1331,7 @@ protected Default(TypeDescription instrumentedType, List explicitAuxiliaryTypes, ClassFileVersion classFileVersion, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, ClassVisitorWrapper classVisitorWrapper, TypeAttributeAppender attributeAppender, FieldPool fieldPool, @@ -1336,6 +1343,7 @@ protected Default(TypeDescription instrumentedType, this.explicitAuxiliaryTypes = explicitAuxiliaryTypes; this.classFileVersion = classFileVersion; this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy; + this.implementationContextFactory = implementationContextFactory; this.classVisitorWrapper = classVisitorWrapper; this.attributeAppender = attributeAppender; this.fieldPool = fieldPool; @@ -1346,18 +1354,20 @@ protected Default(TypeDescription instrumentedType, /** * Creates a type writer for creating a new type. * - * @param methodRegistry The method registry to use for creating the type. - * @param fieldPool The field pool to use. - * @param auxiliaryTypeNamingStrategy A naming strategy for naming auxiliary types. - * @param classVisitorWrapper The class visitor wrapper to apply when creating the type. - * @param attributeAppender The attribute appender to use. - * @param classFileVersion The class file version of the created type. - * @param The best known loaded type for the dynamically created type. + * @param methodRegistry The method registry to use for creating the type. + * @param fieldPool The field pool to use. + * @param auxiliaryTypeNamingStrategy A naming strategy for naming auxiliary types. + * @param implementationContextFactory The implementation context factory to use. + * @param classVisitorWrapper The class visitor wrapper to apply when creating the type. + * @param attributeAppender The attribute appender to use. + * @param classFileVersion The class file version of the created type. + * @param The best known loaded type for the dynamically created type. * @return An appropriate type writer. */ public static TypeWriter forCreation(MethodRegistry.Compiled methodRegistry, FieldPool fieldPool, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, ClassVisitorWrapper classVisitorWrapper, TypeAttributeAppender attributeAppender, ClassFileVersion classFileVersion) { @@ -1367,6 +1377,7 @@ public static TypeWriter forCreation(MethodRegistry.Compiled methodRegist Collections.emptyList(), classFileVersion, auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapper, attributeAppender, fieldPool, @@ -1377,21 +1388,23 @@ public static TypeWriter forCreation(MethodRegistry.Compiled methodRegist /** * Creates a type writer for creating a new type. * - * @param methodRegistry The method registry to use for creating the type. - * @param fieldPool The field pool to use. - * @param auxiliaryTypeNamingStrategy A naming strategy for naming auxiliary types. - * @param classVisitorWrapper The class visitor wrapper to apply when creating the type. - * @param attributeAppender The attribute appender to use. - * @param classFileVersion The minimum class file version of the created type. - * @param classFileLocator The class file locator to use. - * @param methodRebaseResolver The method rebase resolver to use. - * @param targetType The target type that is to be rebased. - * @param The best known loaded type for the dynamically created type. + * @param methodRegistry The method registry to use for creating the type. + * @param fieldPool The field pool to use. + * @param auxiliaryTypeNamingStrategy A naming strategy for naming auxiliary types. + * @param implementationContextFactory The implementation context factory to use. + * @param classVisitorWrapper The class visitor wrapper to apply when creating the type. + * @param attributeAppender The attribute appender to use. + * @param classFileVersion The minimum class file version of the created type. + * @param classFileLocator The class file locator to use. + * @param methodRebaseResolver The method rebase resolver to use. + * @param targetType The target type that is to be rebased. + * @param The best known loaded type for the dynamically created type. * @return An appropriate type writer. */ public static TypeWriter forRebasing(MethodRegistry.Compiled methodRegistry, FieldPool fieldPool, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, ClassVisitorWrapper classVisitorWrapper, TypeAttributeAppender attributeAppender, ClassFileVersion classFileVersion, @@ -1404,6 +1417,7 @@ public static TypeWriter forRebasing(MethodRegistry.Compiled methodRegist methodRebaseResolver.getAuxiliaryTypes(), classFileVersion, auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapper, attributeAppender, fieldPool, @@ -1417,20 +1431,22 @@ public static TypeWriter forRebasing(MethodRegistry.Compiled methodRegist /** * Creates a type writer for creating a new type. * - * @param methodRegistry The method registry to use for creating the type. - * @param fieldPool The field pool to use. - * @param auxiliaryTypeNamingStrategy A naming strategy for naming auxiliary types. - * @param classVisitorWrapper The class visitor wrapper to apply when creating the type. - * @param attributeAppender The attribute appender to use. - * @param classFileVersion The minimum class file version of the created type. - * @param classFileLocator The class file locator to use. - * @param targetType The target type that is to be rebased. - * @param The best known loaded type for the dynamically created type. + * @param methodRegistry The method registry to use for creating the type. + * @param fieldPool The field pool to use. + * @param auxiliaryTypeNamingStrategy A naming strategy for naming auxiliary types. + * @param implementationContextFactory The implementation context factory to use. + * @param classVisitorWrapper The class visitor wrapper to apply when creating the type. + * @param attributeAppender The attribute appender to use. + * @param classFileVersion The minimum class file version of the created type. + * @param classFileLocator The class file locator to use. + * @param targetType The target type that is to be rebased. + * @param The best known loaded type for the dynamically created type. * @return An appropriate type writer. */ public static TypeWriter forRedefinition(MethodRegistry.Compiled methodRegistry, FieldPool fieldPool, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, ClassVisitorWrapper classVisitorWrapper, TypeAttributeAppender attributeAppender, ClassFileVersion classFileVersion, @@ -1442,6 +1458,7 @@ public static TypeWriter forRedefinition(MethodRegistry.Compiled methodRe Collections.emptyList(), classFileVersion, auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapper, attributeAppender, fieldPool, @@ -1454,7 +1471,7 @@ public static TypeWriter forRedefinition(MethodRegistry.Compiled methodRe @Override public DynamicType.Unloaded make() { - Implementation.Context.ExtractableView implementationContext = new Implementation.Context.Default(instrumentedType, + Implementation.Context.ExtractableView implementationContext = implementationContextFactory.make(instrumentedType, auxiliaryTypeNamingStrategy, typeInitializer, classFileVersion); @@ -1475,6 +1492,7 @@ public boolean equals(Object other) { && explicitAuxiliaryTypes.equals(aDefault.explicitAuxiliaryTypes) && classFileVersion.equals(aDefault.classFileVersion) && auxiliaryTypeNamingStrategy.equals(aDefault.auxiliaryTypeNamingStrategy) + && implementationContextFactory.equals(aDefault.implementationContextFactory) && classVisitorWrapper.equals(aDefault.classVisitorWrapper) && attributeAppender.equals(aDefault.attributeAppender) && fieldPool.equals(aDefault.fieldPool) @@ -1490,6 +1508,7 @@ public int hashCode() { result = 31 * result + explicitAuxiliaryTypes.hashCode(); result = 31 * result + classFileVersion.hashCode(); result = 31 * result + auxiliaryTypeNamingStrategy.hashCode(); + result = 31 * result + implementationContextFactory.hashCode(); result = 31 * result + classVisitorWrapper.hashCode(); result = 31 * result + attributeAppender.hashCode(); result = 31 * result + fieldPool.hashCode(); @@ -2252,20 +2271,21 @@ public static class ForInlining extends Default { /** * Creates a new type writer for inling a type into an existing type description. * - * @param instrumentedType The instrumented type that is to be written. - * @param loadedTypeInitializer The loaded type initializer of the instrumented type. - * @param typeInitializer The type initializer of the instrumented type. - * @param explicitAuxiliaryTypes A list of explicit auxiliary types that are to be added to the created dynamic type. - * @param classFileVersion The class file version of the written type. - * @param auxiliaryTypeNamingStrategy A naming strategy that is used for naming auxiliary types. - * @param classVisitorWrapper A class visitor wrapper to apply during instrumentation. - * @param attributeAppender The type attribute appender to apply. - * @param fieldPool The field pool to be used for instrumenting fields. - * @param methodPool The method pool to be used for instrumenting methods. - * @param instrumentedMethods A list of all instrumented methods. - * @param classFileLocator The class file locator to use. - * @param targetType The target type that is to be redefined via inlining. - * @param methodRebaseResolver The method rebase resolver to use. + * @param instrumentedType The instrumented type that is to be written. + * @param loadedTypeInitializer The loaded type initializer of the instrumented type. + * @param typeInitializer The type initializer of the instrumented type. + * @param explicitAuxiliaryTypes A list of explicit auxiliary types that are to be added to the created dynamic type. + * @param classFileVersion The class file version of the written type. + * @param auxiliaryTypeNamingStrategy A naming strategy that is used for naming auxiliary types. + * @param implementationContextFactory The implementation context factory to use. + * @param classVisitorWrapper A class visitor wrapper to apply during instrumentation. + * @param attributeAppender The type attribute appender to apply. + * @param fieldPool The field pool to be used for instrumenting fields. + * @param methodPool The method pool to be used for instrumenting methods. + * @param instrumentedMethods A list of all instrumented methods. + * @param classFileLocator The class file locator to use. + * @param targetType The target type that is to be redefined via inlining. + * @param methodRebaseResolver The method rebase resolver to use. */ protected ForInlining(TypeDescription instrumentedType, LoadedTypeInitializer loadedTypeInitializer, @@ -2273,6 +2293,7 @@ protected ForInlining(TypeDescription instrumentedType, List explicitAuxiliaryTypes, ClassFileVersion classFileVersion, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, ClassVisitorWrapper classVisitorWrapper, TypeAttributeAppender attributeAppender, FieldPool fieldPool, @@ -2287,6 +2308,7 @@ protected ForInlining(TypeDescription instrumentedType, explicitAuxiliaryTypes, classFileVersion, auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapper, attributeAppender, fieldPool, @@ -2642,13 +2664,17 @@ public MethodVisitor visitMethod(int modifiers, String genericSignature, String[] exceptionTypeInternalName) { if (internalName.equals(MethodDescription.TYPE_INITIALIZER_INTERNAL_NAME)) { - TypeInitializerInjection injectedCode = new TypeInitializerInjection(instrumentedType); - this.injectedCode = injectedCode; - return super.visitMethod(injectedCode.getInjectorProxyMethod().getModifiers(), - injectedCode.getInjectorProxyMethod().getInternalName(), - injectedCode.getInjectorProxyMethod().getDescriptor(), - injectedCode.getInjectorProxyMethod().getGenericSignature(), - injectedCode.getInjectorProxyMethod().getExceptionTypes().asErasures().toInternalNames()); + if (implementationContext.isRetainTypeInitializer()) { + return super.visitMethod(modifiers, internalName, descriptor, genericSignature, exceptionTypeInternalName); + } else { + TypeInitializerInjection injectedCode = new TypeInitializerInjection(instrumentedType); + this.injectedCode = injectedCode; + return super.visitMethod(injectedCode.getInjectorProxyMethod().getModifiers(), + injectedCode.getInjectorProxyMethod().getInternalName(), + injectedCode.getInjectorProxyMethod().getDescriptor(), + injectedCode.getInjectorProxyMethod().getGenericSignature(), + injectedCode.getInjectorProxyMethod().getExceptionTypes().asErasures().toInternalNames()); + } } MethodDescription methodDescription = declarableMethods.remove(internalName + descriptor); return methodDescription == RETAIN_METHOD @@ -2896,17 +2922,18 @@ public static class ForCreation extends Default { /** * Creates a new type writer for creating a new type. * - * @param instrumentedType The instrumented type that is to be written. - * @param loadedTypeInitializer The loaded type initializer of the instrumented type. - * @param typeInitializer The type initializer of the instrumented type. - * @param explicitAuxiliaryTypes A list of explicit auxiliary types that are to be added to the created dynamic type. - * @param classFileVersion The class file version of the written type. - * @param auxiliaryTypeNamingStrategy A naming strategy that is used for naming auxiliary types. - * @param classVisitorWrapper A class visitor wrapper to apply during instrumentation. - * @param attributeAppender The type attribute appender to apply. - * @param fieldPool The field pool to be used for instrumenting fields. - * @param methodPool The method pool to be used for instrumenting methods. - * @param instrumentedMethods A list of all instrumented methods. + * @param instrumentedType The instrumented type that is to be written. + * @param loadedTypeInitializer The loaded type initializer of the instrumented type. + * @param typeInitializer The type initializer of the instrumented type. + * @param explicitAuxiliaryTypes A list of explicit auxiliary types that are to be added to the created dynamic type. + * @param classFileVersion The class file version of the written type. + * @param auxiliaryTypeNamingStrategy A naming strategy that is used for naming auxiliary types. + * @param implementationContextFactory The implementation context factory to use. + * @param classVisitorWrapper A class visitor wrapper to apply during instrumentation. + * @param attributeAppender The type attribute appender to apply. + * @param fieldPool The field pool to be used for instrumenting fields. + * @param methodPool The method pool to be used for instrumenting methods. + * @param instrumentedMethods A list of all instrumented methods. */ protected ForCreation(TypeDescription instrumentedType, LoadedTypeInitializer loadedTypeInitializer, @@ -2914,6 +2941,7 @@ protected ForCreation(TypeDescription instrumentedType, List explicitAuxiliaryTypes, ClassFileVersion classFileVersion, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, ClassVisitorWrapper classVisitorWrapper, TypeAttributeAppender attributeAppender, FieldPool fieldPool, @@ -2925,6 +2953,7 @@ protected ForCreation(TypeDescription instrumentedType, explicitAuxiliaryTypes, classFileVersion, auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapper, attributeAppender, fieldPool, @@ -2965,6 +2994,7 @@ public String toString() { ", explicitAuxiliaryTypes=" + explicitAuxiliaryTypes + ", classFileVersion=" + classFileVersion + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", classVisitorWrapper=" + classVisitorWrapper + ", attributeAppender=" + attributeAppender + ", fieldPool=" + fieldPool + diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RebaseDynamicTypeBuilder.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RebaseDynamicTypeBuilder.java index b20543282de..a99759285ec 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RebaseDynamicTypeBuilder.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RebaseDynamicTypeBuilder.java @@ -11,6 +11,7 @@ import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.scaffold.*; +import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.LoadedTypeInitializer; import net.bytebuddy.implementation.attribute.FieldAttributeAppender; import net.bytebuddy.implementation.attribute.MethodAttributeAppender; @@ -47,6 +48,7 @@ public class RebaseDynamicTypeBuilder extends DynamicType.Builder.AbstractBas * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy for naming auxiliary types of the dynamic type. + * @param implementationContextFactory The implementation context factory to use. * @param levelType The type that is to be rebased. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -66,6 +68,7 @@ public class RebaseDynamicTypeBuilder extends DynamicType.Builder.AbstractBas public RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription levelType, List interfaceTypes, int modifiers, @@ -82,6 +85,7 @@ public RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, this(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, joinUniqueRaw(interfaceTypes, levelType.getInterfaces()), modifiers, @@ -105,6 +109,7 @@ public RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy for naming auxiliary types of the dynamic type. + * @param implementationContextFactory The implementation context factory to use. * @param levelType The type that is to be rebased. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -128,6 +133,7 @@ public RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, protected RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription levelType, List interfaceTypes, int modifiers, @@ -146,6 +152,7 @@ protected RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, super(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, interfaceTypes, modifiers, @@ -167,6 +174,7 @@ protected RebaseDynamicTypeBuilder(ClassFileVersion classFileVersion, protected DynamicType.Builder materialize(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription levelType, List interfaceTypes, int modifiers, @@ -183,6 +191,7 @@ protected DynamicType.Builder materialize(ClassFileVersion classFileVersion, return new RebaseDynamicTypeBuilder(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, interfaceTypes, modifiers, @@ -233,6 +242,7 @@ public DynamicType.Unloaded make() { return TypeWriter.Default.forRebasing(compiledMethodRegistry, fieldRegistry.compile(compiledMethodRegistry.getInstrumentedType()), auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapperChain, attributeAppender, classFileVersion, @@ -263,6 +273,7 @@ public String toString() { "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", targetType=" + targetType + ", interfaceTypes=" + interfaceTypes + ", modifiers=" + modifiers + diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RedefinitionDynamicTypeBuilder.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RedefinitionDynamicTypeBuilder.java index 99868488004..eb9000bc863 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RedefinitionDynamicTypeBuilder.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/inline/RedefinitionDynamicTypeBuilder.java @@ -11,6 +11,7 @@ import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.scaffold.*; import net.bytebuddy.dynamic.scaffold.subclass.SubclassImplementationTarget; +import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.LoadedTypeInitializer; import net.bytebuddy.implementation.attribute.FieldAttributeAppender; import net.bytebuddy.implementation.attribute.MethodAttributeAppender; @@ -41,6 +42,7 @@ public class RedefinitionDynamicTypeBuilder extends DynamicType.Builder.Abstr * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy for naming auxiliary types of the dynamic type. + * @param implementationContextFactory The implementation context factory to use. * @param levelType The type that is to be redefined. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -59,6 +61,7 @@ public class RedefinitionDynamicTypeBuilder extends DynamicType.Builder.Abstr public RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription levelType, List interfaceTypes, int modifiers, @@ -74,6 +77,7 @@ public RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, this(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, joinUniqueRaw(interfaceTypes, levelType.getInterfaces()), modifiers, @@ -96,6 +100,7 @@ public RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy for naming auxiliary types of the dynamic type. + * @param implementationContextFactory The implementation context factory to use. * @param levelType The type that is to be redefined. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -118,6 +123,7 @@ public RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, protected RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription levelType, List interfaceTypes, int modifiers, @@ -135,6 +141,7 @@ protected RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, super(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, interfaceTypes, modifiers, @@ -155,6 +162,7 @@ protected RedefinitionDynamicTypeBuilder(ClassFileVersion classFileVersion, protected DynamicType.Builder materialize(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription levelType, List interfaceTypes, int modifiers, @@ -171,6 +179,7 @@ protected DynamicType.Builder materialize(ClassFileVersion classFileVersion, return new RedefinitionDynamicTypeBuilder(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, levelType, interfaceTypes, modifiers, @@ -212,6 +221,7 @@ public DynamicType.Unloaded make() { return TypeWriter.Default.forRedefinition(compiledMethodRegistry, fieldRegistry.compile(compiledMethodRegistry.getInstrumentedType()), auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapperChain, attributeAppender, classFileVersion, @@ -237,6 +247,7 @@ public String toString() { "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", targetType=" + targetType + ", interfaceTypes=" + interfaceTypes + ", modifiers=" + modifiers + diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/subclass/SubclassDynamicTypeBuilder.java b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/subclass/SubclassDynamicTypeBuilder.java index 708e6e99534..47c601963d3 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/subclass/SubclassDynamicTypeBuilder.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/dynamic/scaffold/subclass/SubclassDynamicTypeBuilder.java @@ -10,6 +10,7 @@ import net.bytebuddy.description.type.generic.GenericTypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.scaffold.*; +import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.LoadedTypeInitializer; import net.bytebuddy.implementation.attribute.FieldAttributeAppender; import net.bytebuddy.implementation.attribute.MethodAttributeAppender; @@ -42,6 +43,7 @@ public class SubclassDynamicTypeBuilder extends DynamicType.Builder.AbstractB * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy to apply to auxiliary types. + * @param implementationContextFactory The implementation context factory to use. * @param superType The super class that the dynamic type should extend. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -61,6 +63,7 @@ public class SubclassDynamicTypeBuilder extends DynamicType.Builder.AbstractB public SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription superType, List interfaceTypes, int modifiers, @@ -76,6 +79,7 @@ public SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, this(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, superType, new ArrayList(interfaceTypes), modifiers, @@ -98,6 +102,7 @@ public SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, * @param classFileVersion The class file version for the created dynamic type. * @param namingStrategy The naming strategy for naming the dynamic type. * @param auxiliaryTypeNamingStrategy The naming strategy to apply to auxiliary types. + * @param implementationContextFactory The implementation context factory to use. * @param superType The super class that the dynamic type should extend. * @param interfaceTypes A list of interfaces that should be implemented by the created dynamic type. * @param modifiers The modifiers to be represented by the dynamic type. @@ -121,6 +126,7 @@ public SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, protected SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription superType, List interfaceTypes, int modifiers, @@ -138,6 +144,7 @@ protected SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, super(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, superType, interfaceTypes, modifiers, @@ -158,6 +165,7 @@ protected SubclassDynamicTypeBuilder(ClassFileVersion classFileVersion, protected DynamicType.Builder materialize(ClassFileVersion classFileVersion, NamingStrategy namingStrategy, AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + Implementation.Context.Factory implementationContextFactory, TypeDescription targetType, List interfaceTypes, int modifiers, @@ -174,6 +182,7 @@ protected DynamicType.Builder materialize(ClassFileVersion classFileVersion, return new SubclassDynamicTypeBuilder(classFileVersion, namingStrategy, auxiliaryTypeNamingStrategy, + implementationContextFactory, targetType, interfaceTypes, modifiers, @@ -213,6 +222,7 @@ public DynamicType.Unloaded make() { return TypeWriter.Default.forCreation(compiledMethodRegistry, fieldRegistry.compile(compiledMethodRegistry.getInstrumentedType()), auxiliaryTypeNamingStrategy, + implementationContextFactory, classVisitorWrapperChain, attributeAppender, classFileVersion).make(); @@ -252,6 +262,7 @@ public String toString() { "classFileVersion=" + classFileVersion + ", namingStrategy=" + namingStrategy + ", auxiliaryTypeNamingStrategy=" + auxiliaryTypeNamingStrategy + + ", implementationContextFactory=" + implementationContextFactory + ", targetType=" + targetType + ", interfaceTypes=" + interfaceTypes + ", modifiers=" + modifiers + diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java index b464be39875..c52cd3d0ea2 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/implementation/Implementation.java @@ -408,6 +408,14 @@ interface Context { */ interface ExtractableView extends Context { + /** + * Determines if this implementation context allows for the retention of a static type initializer. + * + * @return {@code true} if the original type initializer can be retained. {@code false} if the original type + * initializer needs to be copied to another method for allowing code injection into the initializer. + */ + boolean isRetainTypeInitializer(); + /** * Returns any {@link net.bytebuddy.implementation.auxiliary.AuxiliaryType} that was registered * with this {@link Implementation.Context}. @@ -477,11 +485,125 @@ public String toString() { } } + /** + * A factory for creating a new implementation context. + */ + interface Factory { + + /** + * Creates a new implementation context. + * + * @param instrumentedType The description of the type that is currently subject of creation. + * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type. + * @param typeInitializer The type initializer of the created instrumented type. + * @param classFileVersion The class file version of the created class. + * @return An implementation context in its extractable view. + */ + ExtractableView make(TypeDescription instrumentedType, + AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + InstrumentedType.TypeInitializer typeInitializer, + ClassFileVersion classFileVersion); + } + + /** + * An implementation context that does not allow for any injections into the static initializer block. This can be useful when + * redefining a class when it is not allowed to add methods to a class what is an implicit requirement when copying the static + * initializer block into another method. + */ + class Disabled implements ExtractableView { + + /** + * The instrumented type. + */ + private final TypeDescription instrumentedType; + + /** + * Creates a new disabled implementation context. + * + * @param instrumentedType The instrumented type. + */ + protected Disabled(TypeDescription instrumentedType) { + this.instrumentedType = instrumentedType; + } + + @Override + public boolean isRetainTypeInitializer() { + return true; + } + + @Override + public List getRegisteredAuxiliaryTypes() { + return Collections.emptyList(); + } + + @Override + public void drain(ClassVisitor classVisitor, TypeWriter.MethodPool methodPool, InjectedCode injectedCode) { + if (injectedCode.isDefined() || methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType)).getSort().isDefined()) { + throw new IllegalStateException("Type initializer definition was explicitly disabled"); + } + } + + @Override + public TypeDescription register(AuxiliaryType auxiliaryType) { + throw new IllegalStateException("Registration of auxiliary types was disabled: " + auxiliaryType); + } + + @Override + public FieldDescription cache(StackManipulation fieldValue, TypeDescription fieldType) { + throw new IllegalStateException("Field values caching was disabled: " + fieldType); + } + + @Override + public boolean equals(Object other) { + return this == other || !(other == null || getClass() != other.getClass()) + && instrumentedType.equals(((Disabled) other).instrumentedType); + } + + @Override + public int hashCode() { + return instrumentedType.hashCode(); + } + + @Override + public String toString() { + return "Implementation.Context.Disabled{" + + "instrumentedType=" + instrumentedType + + '}'; + } + + /** + * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Disabled}. + */ + public enum Factory implements Context.Factory { + + /** + * The singleton instance. + */ + INSTANCE; + + @Override + public ExtractableView make(TypeDescription instrumentedType, + AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + InstrumentedType.TypeInitializer typeInitializer, + ClassFileVersion classFileVersion) { + if (typeInitializer.isDefined()) { + throw new IllegalStateException("Cannot define type initializer which was explicitly disabled: " + typeInitializer); + } + return new Disabled(instrumentedType); + } + + @Override + public String toString() { + return "Implementation.Context.Disabled.Factory." + name(); + } + } + } + /** * A default implementation of an {@link Implementation.Context.ExtractableView} * which serves as its own {@link net.bytebuddy.implementation.auxiliary.AuxiliaryType.MethodAccessorFactory}. */ - class Default implements Implementation.Context.ExtractableView, AuxiliaryType.MethodAccessorFactory { + class Default implements ExtractableView, AuxiliaryType.MethodAccessorFactory { /** * The name suffix to be appended to an accessor method. @@ -556,17 +678,17 @@ class Default implements Implementation.Context.ExtractableView, AuxiliaryType.M private boolean canRegisterFieldCache; /** - * Creates a new implementation context. + * Creates a new default implementation context. * * @param instrumentedType The description of the type that is currently subject of creation. * @param auxiliaryTypeNamingStrategy The naming strategy for naming an auxiliary type. * @param typeInitializer The type initializer of the created instrumented type. * @param classFileVersion The class file version of the created class. */ - public Default(TypeDescription instrumentedType, - AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, - InstrumentedType.TypeInitializer typeInitializer, - ClassFileVersion classFileVersion) { + protected Default(TypeDescription instrumentedType, + AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + InstrumentedType.TypeInitializer typeInitializer, + ClassFileVersion classFileVersion) { this.instrumentedType = instrumentedType; this.auxiliaryTypeNamingStrategy = auxiliaryTypeNamingStrategy; this.typeInitializer = typeInitializer; @@ -624,6 +746,11 @@ public TypeDescription register(AuxiliaryType auxiliaryType) { return dynamicType.getTypeDescription(); } + @Override + public boolean isRetainTypeInitializer() { + return false; + } + @Override public List getRegisteredAuxiliaryTypes() { return new ArrayList(auxiliaryTypes.values()); @@ -1327,6 +1454,30 @@ public String toString() { '}'; } } + + /** + * A factory for creating a {@link net.bytebuddy.implementation.Implementation.Context.Default}. + */ + public enum Factory implements ExtractableView.Factory { + + /** + * The singleton instance. + */ + INSTANCE; + + @Override + public ExtractableView make(TypeDescription instrumentedType, + AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy, + InstrumentedType.TypeInitializer typeInitializer, + ClassFileVersion classFileVersion) { + return new Default(instrumentedType, auxiliaryTypeNamingStrategy, typeInitializer, classFileVersion); + } + + @Override + public String toString() { + return "Implementation.Context.Default.Factory." + name(); + } + } } } diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/ByteBuddyTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/ByteBuddyTest.java index aeb7115370b..3f0bc8f2e60 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/ByteBuddyTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/ByteBuddyTest.java @@ -2,7 +2,6 @@ import net.bytebuddy.asm.ClassVisitorWrapper; import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.modifier.ModifierContributor; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.generic.GenericTypeDescription; @@ -23,8 +22,6 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.Opcodes; -import java.lang.annotation.Retention; - import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; @@ -55,7 +52,7 @@ public class ByteBuddyTest { private ElementMatcher methodMatcher; @Mock - private TypeDescription typeDescription; + private TypeDescription interfaceTypes; @Mock private MethodGraph.Compiler methodGraphCompiler; @@ -69,15 +66,18 @@ public class ByteBuddyTest { @Mock private AuxiliaryType.NamingStrategy auxiliaryTypeNamingStrategy; + @Mock + private Implementation.Context.Factory implementationContextFactory; + @Mock private Implementation implementation; @Before public void setUp() throws Exception { when(modifierContributorForType.getMask()).thenReturn(MASK); - when(typeDescription.isInterface()).thenReturn(true); - when(typeDescription.asErasure()).thenReturn(typeDescription); - when(typeDescription.getSort()).thenReturn(GenericTypeDescription.Sort.NON_GENERIC); + when(interfaceTypes.isInterface()).thenReturn(true); + when(interfaceTypes.asErasure()).thenReturn(interfaceTypes); + when(interfaceTypes.getSort()).thenReturn(GenericTypeDescription.Sort.NON_GENERIC); } @Test @@ -90,11 +90,12 @@ public void testDomainSpecificLanguage() throws Exception { .withDefaultFieldAttributeAppender(fieldAttributeAppenderFactory) .withDefaultMethodAttributeAppender(methodAttributeAppenderFactory) .withIgnoredMethods(methodMatcher) - .withImplementing(typeDescription) + .withImplementing(interfaceTypes) .withMethodGraphCompiler(methodGraphCompiler) .withModifiers(modifierContributorForType) .withNamingStrategy(namingStrategy) - .withNamingStrategy(auxiliaryTypeNamingStrategy)); + .withNamingStrategy(auxiliaryTypeNamingStrategy) + .withContext(implementationContextFactory)); } @Test @@ -106,38 +107,40 @@ public void testDomainSpecificLanguageOnAnnotationTarget() throws Exception { .withDefaultFieldAttributeAppender(fieldAttributeAppenderFactory) .withDefaultMethodAttributeAppender(methodAttributeAppenderFactory) .withIgnoredMethods(methodMatcher) - .withImplementing(typeDescription) + .withImplementing(interfaceTypes) .withMethodGraphCompiler(methodGraphCompiler) .withModifiers(modifierContributorForType) .withNamingStrategy(namingStrategy) .withNamingStrategy(auxiliaryTypeNamingStrategy) + .withContext(implementationContextFactory) .method(methodMatcher).intercept(implementation)); } @SuppressWarnings("unchecked") private void assertProperties(ByteBuddy byteBuddy) { - assertThat(byteBuddy.getTypeAttributeAppender(), is(typeAttributeAppender)); - assertThat(byteBuddy.getClassFileVersion(), is(classFileVersion)); - assertThat(byteBuddy.getDefaultFieldAttributeAppenderFactory(), is(fieldAttributeAppenderFactory)); - assertThat(byteBuddy.getDefaultMethodAttributeAppenderFactory(), is(methodAttributeAppenderFactory)); - assertThat(byteBuddy.getIgnoredMethods(), is((ElementMatcher) methodMatcher)); - assertThat(byteBuddy.getInterfaceTypes().size(), is(1)); - assertThat(byteBuddy.getInterfaceTypes(), hasItem(typeDescription)); - assertThat(byteBuddy.getMethodGraphCompiler(), is(methodGraphCompiler)); - assertThat(byteBuddy.getModifiers().isDefined(), is(true)); - assertThat(byteBuddy.getModifiers().resolve(0), is(MASK)); - assertThat(byteBuddy.getNamingStrategy(), is(namingStrategy)); - assertThat(byteBuddy.getAuxiliaryTypeNamingStrategy(), is(auxiliaryTypeNamingStrategy)); - assertThat(byteBuddy.getClassVisitorWrapperChain(), instanceOf(ClassVisitorWrapper.Chain.class)); + assertThat(byteBuddy.typeAttributeAppender, is(typeAttributeAppender)); + assertThat(byteBuddy.classFileVersion, is(classFileVersion)); + assertThat(byteBuddy.defaultFieldAttributeAppenderFactory, is(fieldAttributeAppenderFactory)); + assertThat(byteBuddy.defaultMethodAttributeAppenderFactory, is(methodAttributeAppenderFactory)); + assertThat(byteBuddy.ignoredMethods, is((ElementMatcher) methodMatcher)); + assertThat(byteBuddy.interfaceTypes.size(), is(1)); + assertThat(byteBuddy.interfaceTypes, hasItem(interfaceTypes)); + assertThat(byteBuddy.methodGraphCompiler, is(methodGraphCompiler)); + assertThat(byteBuddy.modifiers.isDefined(), is(true)); + assertThat(byteBuddy.modifiers.resolve(0), is(MASK)); + assertThat(byteBuddy.namingStrategy, is(namingStrategy)); + assertThat(byteBuddy.auxiliaryTypeNamingStrategy, is(auxiliaryTypeNamingStrategy)); + assertThat(byteBuddy.implementationContextFactory, is(implementationContextFactory)); + assertThat(byteBuddy.classVisitorWrapperChain, instanceOf(ClassVisitorWrapper.Chain.class)); ClassVisitor classVisitor = mock(ClassVisitor.class); - byteBuddy.getClassVisitorWrapperChain().wrap(classVisitor); + byteBuddy.classVisitorWrapperChain.wrap(classVisitor); verify(classVisitorWrapper).wrap(classVisitor); verifyNoMoreInteractions(classVisitorWrapper); } @Test public void testClassFileVersionConstructor() throws Exception { - assertThat(new ByteBuddy(ClassFileVersion.JAVA_V6).getClassFileVersion(), is(ClassFileVersion.JAVA_V6)); + assertThat(new ByteBuddy(ClassFileVersion.JAVA_V6).classFileVersion, is(ClassFileVersion.JAVA_V6)); } @Test diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultTest.java index e8906c0cef1..8484784289b 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefaultTest.java @@ -72,6 +72,9 @@ public class AgentBuilderDefaultTest { @Mock private AgentBuilder.BinaryLocator binaryLocator; + @Mock + private AgentBuilder.DefinitionHandler definitionHandler; + @Mock private AgentBuilder.BinaryLocator.Initialized initialized; @@ -96,10 +99,12 @@ public Object answer(InvocationOnMock invocation) throws Throwable { return classFileTransformers.add((ClassFileTransformer) invocation.getArguments()[0]); } }).when(instrumentation).addTransformer(any(ClassFileTransformer.class), anyBoolean()); - when(byteBuddy.rebase(any(TypeDescription.class), any(ClassFileLocator.class), any(MethodRebaseResolver.MethodNameTransformer.class))) - .thenReturn((DynamicType.Builder) builder); when(builder.make()).thenReturn((DynamicType.Unloaded) unloaded); when(unloaded.getTypeDescription()).thenReturn(typeDescription); + when(definitionHandler.builder(any(TypeDescription.class), + eq(byteBuddy), + any(ClassFileLocator.class), + any(MethodRebaseResolver.MethodNameTransformer.class))).thenReturn((DynamicType.Builder) builder); Map loadedTypeInitializers = new HashMap(); loadedTypeInitializers.put(typeDescription, loadedTypeInitializer); when(unloaded.getLoadedTypeInitializers()).thenReturn(loadedTypeInitializers); @@ -118,6 +123,7 @@ public void testSuccessful() throws Exception { ClassFileTransformer classFileTransformer = new AgentBuilder.Default(byteBuddy) .disableSelfInitialization() .withBinaryLocator(binaryLocator) + .withDefinitionHandler(definitionHandler) .withListener(listener) .rebase(rawMatcher).transform(transformer) .installOn(instrumentation); @@ -139,6 +145,7 @@ public void testSkipRetransformationWithNonMatched() throws Exception { .disableSelfInitialization() .allowRetransformation() .withBinaryLocator(binaryLocator) + .withDefinitionHandler(definitionHandler) .withListener(listener) .rebase(rawMatcher).transform(transformer) .installOn(instrumentation); @@ -149,7 +156,6 @@ public void testSkipRetransformationWithNonMatched() throws Exception { verifyNoMoreInteractions(listener); verify(instrumentation).addTransformer(classFileTransformer, true); verify(instrumentation).getAllLoadedClasses(); - verify(instrumentation, never()).retransformClasses(); verifyNoMoreInteractions(instrumentation); } @@ -160,6 +166,7 @@ public void testSuccessfulWithRetransformationMatched() throws Exception { .disableSelfInitialization() .allowRetransformation() .withBinaryLocator(binaryLocator) + .withDefinitionHandler(definitionHandler) .withListener(listener) .rebase(rawMatcher).transform(transformer) .installOn(instrumentation); @@ -180,6 +187,7 @@ public void testWithError() throws Exception { ClassFileTransformer classFileTransformer = new AgentBuilder.Default(byteBuddy) .disableSelfInitialization() .withBinaryLocator(binaryLocator) + .withDefinitionHandler(definitionHandler) .withListener(listener) .rebase(rawMatcher).transform(transformer) .installOn(instrumentation); @@ -200,6 +208,7 @@ public void testIgnored() throws Exception { ClassFileTransformer classFileTransformer = new AgentBuilder.Default(byteBuddy) .disableSelfInitialization() .withBinaryLocator(binaryLocator) + .withDefinitionHandler(definitionHandler) .withListener(listener) .rebase(rawMatcher).transform(transformer) .installOn(instrumentation); diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefinitionHandlerTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefinitionHandlerTest.java new file mode 100644 index 00000000000..56f6edec6f4 --- /dev/null +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/agent/builder/AgentBuilderDefinitionHandlerTest.java @@ -0,0 +1,63 @@ +package net.bytebuddy.agent.builder; + +import net.bytebuddy.ByteBuddy; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.ClassFileLocator; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.dynamic.scaffold.inline.MethodRebaseResolver; +import net.bytebuddy.test.utility.MockitoRule; +import net.bytebuddy.test.utility.ObjectPropertyAssertion; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.mockito.Mock; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.*; + +public class AgentBuilderDefinitionHandlerTest { + + @Rule + public TestRule mockitoRule = new MockitoRule(this); + + @Mock + private TypeDescription typeDescription; + + @Mock + private ByteBuddy byteBuddy; + + @Mock + private ClassFileLocator classFileLocator; + + @Mock + private MethodRebaseResolver.MethodNameTransformer methodNameTransformer; + + @Mock + private DynamicType.Builder dynamicTypeBuilder; + + @Test + @SuppressWarnings("unchecked") + public void testRebase() throws Exception { + when(byteBuddy.rebase(typeDescription, classFileLocator, methodNameTransformer)).thenReturn((DynamicType.Builder) dynamicTypeBuilder); + assertThat(AgentBuilder.DefinitionHandler.Default.REBASE.builder(typeDescription, byteBuddy, classFileLocator, methodNameTransformer), + is((DynamicType.Builder) dynamicTypeBuilder)); + verify(byteBuddy).rebase(typeDescription, classFileLocator, methodNameTransformer); + verifyNoMoreInteractions(byteBuddy); + } + + @Test + @SuppressWarnings("unchecked") + public void testRedefine() throws Exception { + when(byteBuddy.redefine(typeDescription, classFileLocator)).thenReturn((DynamicType.Builder) dynamicTypeBuilder); + assertThat(AgentBuilder.DefinitionHandler.Default.REDEFINE.builder(typeDescription, byteBuddy, classFileLocator, methodNameTransformer), + is((DynamicType.Builder) dynamicTypeBuilder)); + verify(byteBuddy).redefine(typeDescription, classFileLocator); + verifyNoMoreInteractions(byteBuddy); + } + + @Test + public void testObjectProperties() throws Exception { + ObjectPropertyAssertion.of(AgentBuilder.DefinitionHandler.Default.class).apply(); + } +} diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/scaffold/inline/AbstractDynamicTypeBuilderForInliningTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/scaffold/inline/AbstractDynamicTypeBuilderForInliningTest.java index 09eb09d64fe..fd54f85618b 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/scaffold/inline/AbstractDynamicTypeBuilderForInliningTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/dynamic/scaffold/inline/AbstractDynamicTypeBuilderForInliningTest.java @@ -382,6 +382,14 @@ public MethodVisitor visitMethod(int access, String name, String desc, String si verifyNoMoreInteractions(classVisitorWrapper); } + @Test(expected = IllegalStateException.class) + public void testForbidTypeInitilizerInterception() throws Exception { + createPlain() + .context(Implementation.Context.Disabled.Factory.INSTANCE) + .invokable(isTypeInitializer()).intercept(StubMethod.INSTANCE) + .make(); + } + public @interface Baz { String foo(); diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/AbstractImplementationTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/AbstractImplementationTest.java index 18764c84125..a7edd72a95d 100644 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/AbstractImplementationTest.java +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/AbstractImplementationTest.java @@ -49,6 +49,7 @@ protected DynamicType.Loaded implement(Class target, ClassFileVersion.forCurrentJavaVersion(), new NamingStrategy.SuffixingRandom(SUFFIX), new AuxiliaryType.NamingStrategy.SuffixingRandom(SUFFIX), + Implementation.Context.Default.Factory.INSTANCE, new TypeDescription.ForLoadedType(target), new TypeList.ForLoadedType(Arrays.asList(interfaces)), Opcodes.ACC_PUBLIC, diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDefaultObjectPropertiesTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDefaultObjectPropertiesTest.java deleted file mode 100644 index 99f44384e3b..00000000000 --- a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDefaultObjectPropertiesTest.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.bytebuddy.implementation; - -import net.bytebuddy.test.utility.ObjectPropertyAssertion; -import org.junit.Test; - -public class ImplementationContextDefaultObjectPropertiesTest { - - @Test - public void testObjectProperties() throws Exception { - ObjectPropertyAssertion.of(Implementation.Context.Default.class).applyBasic(); - ObjectPropertyAssertion.of(Implementation.Context.Default.FieldCacheEntry.class).apply(); - ObjectPropertyAssertion.of(Implementation.Context.Default.AccessorMethodDelegation.class).apply(); - ObjectPropertyAssertion.of(Implementation.Context.Default.FieldSetterDelegation.class).apply(); - ObjectPropertyAssertion.of(Implementation.Context.Default.FieldGetterDelegation.class).apply(); - } -} diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDefaultOtherTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDefaultOtherTest.java new file mode 100644 index 00000000000..107e1bcd0e7 --- /dev/null +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDefaultOtherTest.java @@ -0,0 +1,42 @@ +package net.bytebuddy.implementation; + +import net.bytebuddy.ClassFileVersion; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.scaffold.InstrumentedType; +import net.bytebuddy.implementation.auxiliary.AuxiliaryType; +import net.bytebuddy.test.utility.ObjectPropertyAssertion; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.mock; + +public class ImplementationContextDefaultOtherTest { + + @Test + public void testFactory() throws Exception { + assertThat(Implementation.Context.Default.Factory.INSTANCE.make(mock(TypeDescription.class), + mock(AuxiliaryType.NamingStrategy.class), + mock(InstrumentedType.TypeInitializer.class), + mock(ClassFileVersion.class)), instanceOf(Implementation.Context.Default.class)); + } + + @Test + public void testTypeInitializerNotRetained() throws Exception { + assertThat(new Implementation.Context.Default(mock(TypeDescription.class), + mock(AuxiliaryType.NamingStrategy.class), + mock(InstrumentedType.TypeInitializer.class), + mock(ClassFileVersion.class)).isRetainTypeInitializer(), is(false)); + } + + @Test + public void testObjectProperties() throws Exception { + ObjectPropertyAssertion.of(Implementation.Context.Default.class).applyBasic(); + ObjectPropertyAssertion.of(Implementation.Context.Default.FieldCacheEntry.class).apply(); + ObjectPropertyAssertion.of(Implementation.Context.Default.AccessorMethodDelegation.class).apply(); + ObjectPropertyAssertion.of(Implementation.Context.Default.FieldSetterDelegation.class).apply(); + ObjectPropertyAssertion.of(Implementation.Context.Default.FieldGetterDelegation.class).apply(); + ObjectPropertyAssertion.of(Implementation.Context.Default.Factory.class).apply(); + } +} diff --git a/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDisabledTest.java b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDisabledTest.java new file mode 100644 index 00000000000..10550fdfe44 --- /dev/null +++ b/byte-buddy-dep/src/test/java/net/bytebuddy/implementation/ImplementationContextDisabledTest.java @@ -0,0 +1,102 @@ +package net.bytebuddy.implementation; + +import net.bytebuddy.ClassFileVersion; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.scaffold.InstrumentedType; +import net.bytebuddy.dynamic.scaffold.TypeWriter; +import net.bytebuddy.implementation.auxiliary.AuxiliaryType; +import net.bytebuddy.implementation.bytecode.StackManipulation; +import net.bytebuddy.test.utility.MockitoRule; +import net.bytebuddy.test.utility.ObjectPropertyAssertion; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TestRule; +import org.mockito.Mock; +import org.objectweb.asm.ClassVisitor; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.Is.is; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ImplementationContextDisabledTest { + + @Rule + public TestRule mockitoRule = new MockitoRule(this); + + @Mock + private TypeDescription instrumentedType; + + @Mock + private TypeWriter.MethodPool methodPool; + + @Mock + private TypeWriter.MethodPool.Record record; + + @Mock + private Implementation.Context.ExtractableView.InjectedCode injectedCode; + + @Before + public void setUp() throws Exception { + when(methodPool.target(new MethodDescription.Latent.TypeInitializer(instrumentedType))).thenReturn(record); + } + + @Test + public void testFactory() throws Exception { + assertThat(Implementation.Context.Disabled.Factory.INSTANCE.make(instrumentedType, + mock(AuxiliaryType.NamingStrategy.class), + mock(InstrumentedType.TypeInitializer.class), + mock(ClassFileVersion.class)), is((Implementation.Context.ExtractableView) new Implementation.Context.Disabled(instrumentedType))); + } + + @Test(expected = IllegalStateException.class) + public void testFactoryWithTypeInitializer() throws Exception { + InstrumentedType.TypeInitializer typeInitializer = mock(InstrumentedType.TypeInitializer.class); + when(typeInitializer.isDefined()).thenReturn(true); + Implementation.Context.Disabled.Factory.INSTANCE.make(instrumentedType, + mock(AuxiliaryType.NamingStrategy.class), + typeInitializer, + mock(ClassFileVersion.class)); + } + + @Test + public void testRetainTypeInitializer() throws Exception { + assertThat(new Implementation.Context.Disabled(instrumentedType).isRetainTypeInitializer(), is(true)); + } + + @Test + public void testAuxiliaryTypes() throws Exception { + assertThat(new Implementation.Context.Disabled(instrumentedType).getRegisteredAuxiliaryTypes().size(), is(0)); + } + + @Test(expected = IllegalStateException.class) + public void testCannotCacheValue() throws Exception { + new Implementation.Context.Disabled(instrumentedType).cache(mock(StackManipulation.class), mock(TypeDescription.class)); + } + + @Test(expected = IllegalStateException.class) + public void testCannotRegisterAuxiliaryType() throws Exception { + new Implementation.Context.Disabled(instrumentedType).register(mock(AuxiliaryType.class)); + } + + @Test(expected = IllegalStateException.class) + public void testDrainWithInjectedCode() throws Exception { + when(injectedCode.isDefined()).thenReturn(true); + when(record.getSort()).thenReturn(TypeWriter.MethodPool.Record.Sort.SKIPPED); + new Implementation.Context.Disabled(instrumentedType).drain(mock(ClassVisitor.class), methodPool, injectedCode); + } + + @Test(expected = IllegalStateException.class) + public void testDrainWithMatchedCode() throws Exception { + when(record.getSort()).thenReturn(TypeWriter.MethodPool.Record.Sort.DEFINED); + new Implementation.Context.Disabled(instrumentedType).drain(mock(ClassVisitor.class), methodPool, injectedCode); + } + + @Test + public void testObjectProperties() throws Exception { + ObjectPropertyAssertion.of(Implementation.Context.Disabled.class).apply(); + ObjectPropertyAssertion.of(Implementation.Context.Disabled.Factory.class).apply(); + } +}