package net.bytebuddy.dynamic.scaffold.inline; import net.bytebuddy.ByteBuddy; import net.bytebuddy.description.annotation.AnnotationList; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.field.FieldList; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.method.MethodList; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.description.type.TypeList; import net.bytebuddy.dynamic.ClassFileLocator; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.dynamic.scaffold.TypeValidation; import net.bytebuddy.implementation.Implementation; import net.bytebuddy.implementation.MethodCall; import net.bytebuddy.implementation.StubMethod; import net.bytebuddy.implementation.attribute.AnnotationRetention; import net.bytebuddy.implementation.bytecode.constant.TextConstant; import net.bytebuddy.implementation.bytecode.member.MethodReturn; import net.bytebuddy.test.utility.JavaVersionRule; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import org.junit.Test; import java.lang.reflect.Field; import java.net.URL; import java.net.URLClassLoader; import java.util.Collections; import java.util.List; import static net.bytebuddy.matcher.ElementMatchers.any; import static net.bytebuddy.matcher.ElementMatchers.named; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class RedefinitionDynamicTypeBuilderTest extends AbstractDynamicTypeBuilderForInliningTest { private static final String FOO = "foo", BAR = "bar"; private static final String DEFAULT_METHOD_INTERFACE = "net.bytebuddy.test.precompiled.SingleDefaultMethodInterface"; @Override protected DynamicType.Builder<?> create(Class<?> type) { return new ByteBuddy().redefine(type); } @Override protected DynamicType.Builder<?> createDisabledContext() { return new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE).redefine(Foo.class); } @Override protected DynamicType.Builder createDisabledRetention(Class<?> annotatedClass) { return new ByteBuddy().with(AnnotationRetention.DISABLED).redefine(annotatedClass); } @Override protected DynamicType.Builder<?> createPlain() { return new ByteBuddy().redefine(Foo.class); } @Override protected DynamicType.Builder<?> create(TypeDescription typeDescription, ClassFileLocator classFileLocator) { return new ByteBuddy().redefine(typeDescription, classFileLocator); } @Override protected DynamicType.Builder<?> createPlainWithoutValidation() { return new ByteBuddy().with(TypeValidation.DISABLED).redefine(Foo.class); } @Test public void testConstructorRetentionNoAuxiliaryType() throws Exception { DynamicType.Unloaded<?> dynamicType = new ByteBuddy() .redefine(Bar.class) .make(); assertThat(dynamicType.getAuxiliaryTypes().size(), is(0)); Class<?> type = dynamicType.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER).getLoaded(); assertThat(type.getDeclaredConstructors().length, is(1)); assertThat(type.getDeclaredMethods().length, is(0)); Field field = type.getDeclaredField(BAR); assertThat(field.get(type.getDeclaredConstructor(String.class).newInstance(FOO)), is((Object) FOO)); } @Test public void testConstructorRebaseSingleAuxiliaryType() throws Exception { DynamicType.Unloaded<?> dynamicType = new ByteBuddy() .redefine(Bar.class) .constructor(any()).intercept(MethodCall.invoke(Object.class.getDeclaredConstructor())) .make(); assertThat(dynamicType.getAuxiliaryTypes().size(), is(0)); Class<?> type = dynamicType.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER).getLoaded(); assertThat(type.getDeclaredConstructors().length, is(1)); assertThat(type.getDeclaredMethods().length, is(0)); Field field = type.getDeclaredField(BAR); assertThat(field.get(type.getDeclaredConstructor(String.class).newInstance(FOO)), nullValue(Object.class)); } @Test public void testMethodRebase() throws Exception { DynamicType.Unloaded<?> dynamicType = new ByteBuddy() .redefine(Qux.class) .method(named(BAR)).intercept(StubMethod.INSTANCE) .make(); assertThat(dynamicType.getAuxiliaryTypes().size(), is(0)); Class<?> type = dynamicType.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER).getLoaded(); assertThat(type.getDeclaredConstructors().length, is(1)); assertThat(type.getDeclaredMethods().length, is(2)); assertThat(type.getDeclaredMethod(FOO).invoke(null), nullValue(Object.class)); assertThat(type.getDeclaredField(FOO).get(null), is((Object) FOO)); assertThat(type.getDeclaredMethod(BAR).invoke(null), nullValue(Object.class)); assertThat(type.getDeclaredField(FOO).get(null), is((Object) FOO)); } @Test @JavaVersionRule.Enforce(8) public void testDefaultInterfaceSubInterface() throws Exception { Class<?> interfaceType = Class.forName(DEFAULT_METHOD_INTERFACE); Class<?> dynamicInterfaceType = new ByteBuddy() .redefine(interfaceType) .method(named(FOO)).intercept(new Implementation.Simple(new TextConstant(BAR), MethodReturn.REFERENCE)) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); Class<?> dynamicClassType = new ByteBuddy() .subclass(dynamicInterfaceType) .make() .load(dynamicInterfaceType.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(dynamicClassType.getMethod(FOO).invoke(dynamicClassType.getDeclaredConstructor().newInstance()), is((Object) BAR)); assertThat(dynamicInterfaceType.getDeclaredMethods().length, is(1)); assertThat(dynamicClassType.getDeclaredMethods().length, is(0)); } @Test @SuppressWarnings("unchecked") public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(RedefinitionDynamicTypeBuilder.class).create(new ObjectPropertyAssertion.Creator<List<?>>() { @Override public List<?> create() { TypeDescription typeDescription = mock(TypeDescription.class); when(typeDescription.asErasure()).thenReturn(typeDescription); return Collections.singletonList(typeDescription); } }).create(new ObjectPropertyAssertion.Creator<TypeDescription>() { @Override public TypeDescription create() { TypeDescription rawTypeDescription = mock(TypeDescription.class); when(rawTypeDescription.getDeclaredAnnotations()).thenReturn(new AnnotationList.Empty()); when(rawTypeDescription.getTypeVariables()).thenReturn(new TypeList.Generic.Empty()); TypeDescription.Generic typeDescription = mock(TypeDescription.Generic.class); when(typeDescription.asErasure()).thenReturn(rawTypeDescription); when(typeDescription.asGenericType()).thenReturn(typeDescription); when(rawTypeDescription.getInterfaces()).thenReturn(new TypeList.Generic.Explicit(typeDescription)); when(rawTypeDescription.getDeclaredFields()).thenReturn(new FieldList.Empty<FieldDescription.InDefinedShape>()); when(rawTypeDescription.getDeclaredMethods()).thenReturn(new MethodList.Empty<MethodDescription.InDefinedShape>()); return rawTypeDescription; } }).apply(); } public static class Bar { public final String bar; public Bar(String bar) { this.bar = bar; } } public static class Qux { public static String foo; public static String foo() { try { return foo; } finally { foo = FOO; } } public static String bar() { try { return foo; } finally { foo = FOO; } } } }