package net.bytebuddy.dynamic.scaffold.inline; import net.bytebuddy.ByteBuddy; import net.bytebuddy.description.annotation.AnnotationDescription; 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.PackageDescription; 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.MethodDelegation; import net.bytebuddy.implementation.StubMethod; import net.bytebuddy.implementation.SuperMethodCall; import net.bytebuddy.implementation.attribute.AnnotationRetention; import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.test.utility.JavaVersionRule; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import net.bytebuddy.test.visibility.PackageAnnotation; import net.bytebuddy.test.visibility.Sample; import org.hamcrest.CoreMatchers; import org.junit.Test; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; 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.*; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; public class RebaseDynamicTypeBuilderTest 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<?> createPlain() { return create(Foo.class); } @Override protected DynamicType.Builder<?> createDisabledContext() { return new ByteBuddy().with(Implementation.Context.Disabled.Factory.INSTANCE).rebase(Foo.class); } @Override protected DynamicType.Builder createDisabledRetention(Class<?> annotatedClass) { return new ByteBuddy().with(AnnotationRetention.DISABLED).rebase(annotatedClass); } @Override protected DynamicType.Builder<?> create(Class<?> type) { return new ByteBuddy().rebase(type); } @Override protected DynamicType.Builder<?> create(TypeDescription typeDescription, ClassFileLocator classFileLocator) { return new ByteBuddy().rebase(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() .rebase(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() .rebase(Bar.class) .constructor(any()).intercept(SuperMethodCall.INSTANCE) .make(); assertThat(dynamicType.getAuxiliaryTypes().size(), is(1)); Class<?> type = dynamicType.load(new URLClassLoader(new URL[0], null), ClassLoadingStrategy.Default.WRAPPER).getLoaded(); assertThat(type.getDeclaredConstructors().length, is(2)); 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 testMethodRebase() throws Exception { DynamicType.Unloaded<?> dynamicType = new ByteBuddy() .rebase(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(3)); 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 public void testPackageRebasement() throws Exception { Class<?> packageType = new ByteBuddy() .rebase(Sample.class.getPackage(), ClassFileLocator.ForClassLoader.of(getClass().getClassLoader())) .annotateType(AnnotationDescription.Builder.ofType(Baz.class).build()) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.CHILD_FIRST) .getLoaded(); assertThat(packageType.getSimpleName(), CoreMatchers.is(PackageDescription.PACKAGE_CLASS_NAME)); assertThat(packageType.getName(), CoreMatchers.is(Sample.class.getPackage().getName() + "." + PackageDescription.PACKAGE_CLASS_NAME)); assertThat(packageType.getModifiers(), CoreMatchers.is(PackageDescription.PACKAGE_MODIFIERS)); assertThat(packageType.getDeclaredFields().length, CoreMatchers.is(0)); assertThat(packageType.getDeclaredMethods().length, CoreMatchers.is(0)); assertThat(packageType.getDeclaredAnnotations().length, CoreMatchers.is(2)); assertThat(packageType.getAnnotation(PackageAnnotation.class), notNullValue(PackageAnnotation.class)); assertThat(packageType.getAnnotation(Baz.class), notNullValue(Baz.class)); } @Test public void testRebaseOfRenamedType() throws Exception { Class<?> rebased = new ByteBuddy() .rebase(Sample.class) .name(Sample.class.getName() + FOO) .constructor(ElementMatchers.any()) .intercept(SuperMethodCall.INSTANCE) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(rebased.getName(), is(Sample.class.getName() + FOO)); assertThat(rebased.getDeclaredConstructors().length, is(2)); } @Test(expected = IllegalStateException.class) public void testCannotRebaseDefinedMethod() throws Exception { new ByteBuddy() .rebase(Foo.class) .defineMethod(FOO, void.class).intercept(SuperMethodCall.INSTANCE) .make(); } @Test @JavaVersionRule.Enforce(8) public void testDefaultInterfaceSubInterface() throws Exception { Class<?> interfaceType = Class.forName(DEFAULT_METHOD_INTERFACE); Class<?> dynamicInterfaceType = new ByteBuddy() .rebase(interfaceType) .method(named(FOO)).intercept(MethodDelegation.to(InterfaceOverrideInterceptor.class)) .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) (FOO + BAR))); assertThat(dynamicInterfaceType.getDeclaredMethods().length, is(3)); assertThat(dynamicClassType.getDeclaredMethods().length, is(0)); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(RebaseDynamicTypeBuilder.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.asErasure()).thenReturn(rawTypeDescription); when(rawTypeDescription.getDeclaredAnnotations()).thenReturn(new AnnotationList.Empty()); when(rawTypeDescription.getTypeVariables()).thenReturn(new TypeList.Generic.Empty()); TypeDescription.Generic typeDescription = mock(TypeDescription.Generic.class); when(typeDescription.asGenericType()).thenReturn(typeDescription); when(typeDescription.asErasure()).thenReturn(rawTypeDescription); 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(); } @Retention(RetentionPolicy.RUNTIME) public @interface Baz { /* empty */ } 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; } } } }