package net.bytebuddy.implementation;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.description.modifier.TypeManifestation;
import net.bytebuddy.description.modifier.Visibility;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.TargetType;
import net.bytebuddy.dynamic.loading.ByteArrayClassLoader;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.dynamic.loading.PackageDefinitionStrategy;
import net.bytebuddy.implementation.bind.annotation.Super;
import net.bytebuddy.test.utility.ClassFileExtraction;
import org.junit.Test;
import java.io.Serializable;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static net.bytebuddy.matcher.ElementMatchers.named;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
public class MethodDelegationSuperTest {
private static final String FOO = "foo", BAR = "bar", QUX = "qux";
@Test
public void testSuperInstance() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(Baz.class))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(), is((Object) (FOO + QUX)));
}
@Test
public void testSuperInterface() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(FooBar.class))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(), is((Object) (FOO + QUX)));
}
@Test
public void testSuperInstanceUnsafe() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(QuxBaz.class))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(), is((Object) (FOO + QUX)));
}
@Test
public void testBridgeMethodResolution() throws Exception {
DynamicType.Loaded<Bar> loaded = new ByteBuddy()
.subclass(Bar.class)
.method(isDeclaredBy(Bar.class))
.intercept(MethodDelegation.to(GenericBaz.class))
.make()
.load(Bar.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Bar instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(BAR), is(BAR + QUX));
}
@Test(expected = AbstractMethodError.class)
public void testSuperCallOnAbstractMethod() throws Exception {
DynamicType.Loaded<FooBarQuxBaz> loaded = new ByteBuddy()
.subclass(FooBarQuxBaz.class)
.method(isDeclaredBy(FooBarQuxBaz.class))
.intercept(MethodDelegation.to(FooBar.class))
.make()
.load(FooBarQuxBaz.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
loaded.getLoaded().getDeclaredConstructor().newInstance().qux();
}
@Test
public void testSerializableProxy() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(SerializationCheck.class))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(), is((Object) (FOO + QUX)));
}
@Test
public void testTargetTypeProxy() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(TargetTypeTest.class))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(), is((Object) (FOO + QUX)));
}
@Test
public void testExplicitTypeProxy() throws Exception {
DynamicType.Loaded<Foo> loaded = new ByteBuddy()
.subclass(Foo.class)
.method(isDeclaredBy(Foo.class))
.intercept(MethodDelegation.to(ExplicitTypeTest.class))
.make()
.load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Foo instance = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(instance.qux(), is((Object) (FOO + QUX)));
}
@Test
public void testFinalType() throws Exception {
ClassLoader classLoader = new ByteArrayClassLoader(ClassLoadingStrategy.BOOTSTRAP_LOADER, ClassFileExtraction.of(SimpleInterceptor.class));
Class<?> type = new ByteBuddy()
.rebase(FinalType.class)
.modifiers(TypeManifestation.PLAIN, Visibility.PUBLIC)
.method(named(FOO)).intercept(ExceptionMethod.throwing(RuntimeException.class))
.method(named(BAR)).intercept(MethodDelegation.to(SimpleInterceptor.class))
.make()
.load(classLoader, ClassLoadingStrategy.Default.INJECTION)
.getLoaded();
assertThat(type.getDeclaredMethod(BAR).invoke(type.getDeclaredConstructor().newInstance()), is((Object) FOO));
}
public interface Qux {
Object qux();
}
public static class Foo implements Qux {
@Override
public Object qux() {
return FOO;
}
}
public static class Baz {
public static String baz(@Super Foo foo) {
assertThat(foo, not(instanceOf(Serializable.class)));
return foo.qux() + QUX;
}
}
public static class FooBar {
public static String baz(@Super Qux foo) {
assertThat(foo, not(instanceOf(Serializable.class)));
return foo.qux() + QUX;
}
}
public static class QuxBaz {
public static String baz(@Super(strategy = Super.Instantiation.UNSAFE) Foo foo) {
assertThat(foo, not(instanceOf(Serializable.class)));
return foo.qux() + QUX;
}
}
public abstract static class FooBarQuxBaz implements Qux {
@Override
public abstract Object qux();
}
public static class GenericBase<T> {
public T qux(T value) {
return value;
}
}
public static class Bar extends GenericBase<String> {
@Override
public String qux(String value) {
return super.qux(value);
}
}
public static class GenericBaz {
public static String baz(String value, @Super GenericBase<String> foo) {
assertThat(foo, not(instanceOf(Serializable.class)));
return foo.qux(value) + QUX;
}
}
public static class SerializationCheck {
public static String baz(@Super(serializableProxy = true) Foo foo) {
assertThat(foo, instanceOf(Serializable.class));
return foo.qux() + QUX;
}
}
public static class TargetTypeTest {
public static String baz(@Super(proxyType = TargetType.class) Object proxy) throws Exception {
assertThat(proxy, instanceOf(Foo.class));
return Foo.class.getDeclaredMethod(QUX).invoke(proxy) + QUX;
}
}
public static class ExplicitTypeTest {
public static String baz(@Super(proxyType = Qux.class) Object proxy) throws Exception {
assertThat(proxy, instanceOf(Qux.class));
assertThat(proxy, not(instanceOf(Foo.class)));
return Qux.class.getDeclaredMethod(QUX).invoke(proxy) + QUX;
}
}
public static final class FinalType {
public Object foo() {
return FOO;
}
public Object bar() {
return null;
}
}
public static class SimpleInterceptor {
public static Object intercept(@Super FinalType finalType) {
return finalType.foo();
}
}
}