package net.bytebuddy.implementation;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.DynamicType;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.bind.annotation.Argument;
import net.bytebuddy.implementation.bind.annotation.FieldProxy;
import org.junit.Before;
import org.junit.Test;
import java.io.Serializable;
import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.assertThat;
public class MethodDelegationFieldProxyTest {
private static final String FOO = "foo", BAR = "bar", QUX = "qux";
@Before
public void setUp() throws Exception {
ExplicitStatic.foo = FOO;
}
@Test
public void testExplicitFieldAccessSimplex() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(Swap.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(explicit.foo, is(FOO));
explicit.swap();
assertThat(explicit.foo, is(FOO + BAR));
}
@Test
public void testExplicitFieldAccessDuplex() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(SwapDuplex.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(explicit.foo, is(FOO));
explicit.swap();
assertThat(explicit.foo, is(FOO + BAR));
}
@Test
public void testExplicitFieldAccessSerializableSimplex() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(SwapSerializable.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(explicit.foo, is(FOO));
explicit.swap();
assertThat(explicit.foo, is(FOO + BAR));
}
@Test
public void testExplicitFieldAccessSerializableDuplex() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(SwapSerializableDuplex.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(explicit.foo, is(FOO));
explicit.swap();
assertThat(explicit.foo, is(FOO + BAR));
}
@Test
public void testExplicitFieldAccessStatic() throws Exception {
DynamicType.Loaded<ExplicitStatic> loaded = new ByteBuddy()
.subclass(ExplicitStatic.class)
.method(isDeclaredBy(ExplicitStatic.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(Swap.class))
.make()
.load(ExplicitStatic.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ExplicitStatic explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(ExplicitStatic.foo, is(FOO));
explicit.swap();
assertThat(ExplicitStatic.foo, is(FOO + BAR));
}
@Test
public void testExplicitFieldAccessStaticDuplex() throws Exception {
DynamicType.Loaded<ExplicitStatic> loaded = new ByteBuddy()
.subclass(ExplicitStatic.class)
.method(isDeclaredBy(ExplicitStatic.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(SwapDuplex.class))
.make()
.load(ExplicitStatic.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ExplicitStatic explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(ExplicitStatic.foo, is(FOO));
explicit.swap();
assertThat(ExplicitStatic.foo, is(FOO + BAR));
}
@Test
public void testImplicitFieldGetterAccess() throws Exception {
DynamicType.Loaded<ImplicitGetter> loaded = new ByteBuddy()
.subclass(ImplicitGetter.class)
.method(isDeclaredBy(ImplicitGetter.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(GetInterceptor.class))
.make()
.load(ImplicitGetter.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ImplicitGetter implicitGetter = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(implicitGetter.foo, is(FOO));
assertThat(implicitGetter.getFoo(), is(FOO + BAR));
assertThat(implicitGetter.foo, is(FOO + BAR));
}
@Test
public void testImplicitFieldSetterAccess() throws Exception {
DynamicType.Loaded<ImplicitSetter> loaded = new ByteBuddy()
.subclass(ImplicitSetter.class)
.method(isDeclaredBy(ImplicitSetter.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(SetInterceptor.class))
.make()
.load(ImplicitSetter.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ImplicitSetter implicitSetter = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(implicitSetter.foo, is(FOO));
implicitSetter.setFoo(BAR);
assertThat(implicitSetter.foo, is(FOO + BAR));
}
@Test
public void testImplicitFieldGetterAccessDuplex() throws Exception {
DynamicType.Loaded<ImplicitGetter> loaded = new ByteBuddy()
.subclass(ImplicitGetter.class)
.method(isDeclaredBy(ImplicitGetter.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(GetInterceptorDuplex.class))
.make()
.load(ImplicitGetter.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ImplicitGetter implicitGetter = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(implicitGetter.foo, is(FOO));
assertThat(implicitGetter.getFoo(), is(FOO + BAR));
assertThat(implicitGetter.foo, is(FOO + BAR));
}
@Test
public void testImplicitFieldSetterAccessDuplex() throws Exception {
DynamicType.Loaded<ImplicitSetter> loaded = new ByteBuddy()
.subclass(ImplicitSetter.class)
.method(isDeclaredBy(ImplicitSetter.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(SetInterceptorDuplex.class))
.make()
.load(ImplicitSetter.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ImplicitSetter implicitSetter = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(implicitSetter.foo, is(FOO));
implicitSetter.setFoo(BAR);
assertThat(implicitSetter.foo, is(FOO + BAR));
}
@Test
public void testExplicitFieldAccessImplicitTarget() throws Exception {
DynamicType.Loaded<ExplicitInherited> loaded = new ByteBuddy()
.subclass(ExplicitInherited.class)
.method(isDeclaredBy(ExplicitInherited.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(Swap.class))
.make()
.load(ExplicitInherited.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ExplicitInherited explicitInherited = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(((Explicit) explicitInherited).foo, is(FOO));
assertThat(explicitInherited.foo, is(QUX));
explicitInherited.swap();
assertThat(((Explicit) explicitInherited).foo, is(FOO));
assertThat(explicitInherited.foo, is(QUX + BAR));
}
@Test
public void testExplicitFieldAccessExplicitTarget() throws Exception {
DynamicType.Loaded<ExplicitInherited> loaded = new ByteBuddy()
.subclass(ExplicitInherited.class)
.method(isDeclaredBy(ExplicitInherited.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(SwapInherited.class))
.make()
.load(ExplicitInherited.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
ExplicitInherited explicitInherited = loaded.getLoaded().getDeclaredConstructor().newInstance();
assertThat(((Explicit) explicitInherited).foo, is(FOO));
assertThat(explicitInherited.foo, is(QUX));
explicitInherited.swap();
assertThat(((Explicit) explicitInherited).foo, is(FOO + BAR));
assertThat(explicitInherited.foo, is(QUX));
}
@Test(expected = IllegalArgumentException.class)
public void testFinalFieldSimplex() throws Exception {
new ByteBuddy()
.subclass(FinalField.class)
.method(isDeclaredBy(FinalField.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(Swap.class))
.make();
}
@Test(expected = UnsupportedOperationException.class)
public void testFinalFieldDuplex() throws Exception {
DynamicType.Loaded<FinalField> loaded = new ByteBuddy()
.subclass(FinalField.class)
.method(isDeclaredBy(FinalField.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(SwapDuplex.class))
.make()
.load(FinalField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
loaded.getLoaded().getDeclaredConstructor().newInstance().method();
}
@Test(expected = ClassCastException.class)
public void testIncompatibleGetterTypeThrowsException() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(GetterIncompatible.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
explicit.swap();
}
@Test(expected = ClassCastException.class)
public void testIncompatibleSetterTypeThrowsException() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(Get.class, Set.class)).to(SetterIncompatible.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
explicit.swap();
}
@Test(expected = ClassCastException.class)
public void testIncompatibleTypeThrowsExceptionGetDuplex() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(GetterIncompatibleDuplex.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
explicit.swap();
}
@Test(expected = ClassCastException.class)
public void testIncompatibleTypeThrowsExceptionSetDuplex() throws Exception {
DynamicType.Loaded<Explicit> loaded = new ByteBuddy()
.subclass(Explicit.class)
.method(isDeclaredBy(Explicit.class))
.intercept(MethodDelegation.withDefaultConfiguration().withBinders(FieldProxy.Binder.install(GetSet.class)).to(SetterIncompatibleDuplex.class))
.make()
.load(Explicit.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER);
Explicit explicit = loaded.getLoaded().getDeclaredConstructor().newInstance();
explicit.swap();
}
@Test(expected = IllegalArgumentException.class)
public void testGetterTypeDoesNotDeclareCorrectMethodThrowsException() throws Exception {
FieldProxy.Binder.install(Serializable.class, Set.class);
}
@Test(expected = IllegalArgumentException.class)
public void testSetterTypeDoesNotDeclareCorrectMethodThrowsException() throws Exception {
FieldProxy.Binder.install(Get.class, Serializable.class);
}
@Test(expected = IllegalArgumentException.class)
public void testGetterTypeDoesInheritFromOtherTypeThrowsException() throws Exception {
FieldProxy.Binder.install(GetInherited.class, Set.class);
}
@Test(expected = IllegalArgumentException.class)
public void testSetterTypeDoesInheritFromOtherTypeThrowsException() throws Exception {
FieldProxy.Binder.install(Get.class, SetInherited.class);
}
@Test(expected = IllegalArgumentException.class)
public void testGetterTypeNonPublicThrowsException() throws Exception {
FieldProxy.Binder.install(GetPrivate.class, Set.class);
}
@Test(expected = IllegalArgumentException.class)
public void testSetterTypeNonPublicThrowsException() throws Exception {
FieldProxy.Binder.install(Get.class, SetPrivate.class);
}
@Test(expected = IllegalArgumentException.class)
public void testSetterTypeIncorrectSignatureThrowsException() throws Exception {
FieldProxy.Binder.install(GetIncorrect.class, Set.class);
}
@Test(expected = IllegalArgumentException.class)
public void testGetterTypeIncorrectSignatureThrowsException() throws Exception {
FieldProxy.Binder.install(Get.class, SetIncorrect.class);
}
@Test(expected = IllegalArgumentException.class)
public void testGetterTypeNotInterfaceThrowsException() throws Exception {
FieldProxy.Binder.install(Object.class, Set.class);
}
@Test(expected = IllegalArgumentException.class)
public void testSetterTypeNotInterfaceThrowsException() throws Exception {
FieldProxy.Binder.install(Get.class, Object.class);
}
@Test(expected = IllegalArgumentException.class)
public void testDuplexTooManyMethodsThrowsException() throws Exception {
FieldProxy.Binder.install(GetSetTooManyMethods.class);
}
@Test(expected = IllegalArgumentException.class)
public void testDuplexNonPublicThrowsException() throws Exception {
FieldProxy.Binder.install(GetSetNonPublic.class);
}
@Test(expected = IllegalArgumentException.class)
public void testDuplexInheritedThrowsException() throws Exception {
FieldProxy.Binder.install(GetSetInherited.class);
}
@Test(expected = IllegalArgumentException.class)
public void testSetterTypeIncorrectSignatureDuplexThrowsException() throws Exception {
FieldProxy.Binder.install(GetSetSetIncorrect.class);
}
@Test(expected = IllegalArgumentException.class)
public void testGetterTypeIncorrectSignatureDuplexThrowsException() throws Exception {
FieldProxy.Binder.install(GetSetGetIncorrect.class);
}
@Test(expected = IllegalArgumentException.class)
public void testTypeNotInterfaceDuplexThrowsException() throws Exception {
FieldProxy.Binder.install(Object.class);
}
public interface Get<T> {
T get();
}
public interface Set<T> {
void set(T value);
}
public interface GetInherited<T> extends Get<T> {
/* empty */
}
public interface SetInherited<T> extends Set<T> {
/* empty */
}
private interface GetPrivate<T> {
T get();
}
private interface SetPrivate<T> {
void set(T value);
}
public interface GetIncorrect<T> {
T get(Object value);
}
public interface SetIncorrect<T> {
Object set(T value);
}
public interface GetSet<T> {
T get();
void set(T value);
}
public interface GetSetGetIncorrect<T> {
String get();
void set(T value);
}
public interface GetSetSetIncorrect<T> {
T get();
void set(String value);
}
interface GetSetNonPublic<T> {
T get();
void set(T value);
}
public interface GetSetTooManyMethods<T> {
T get();
void set(String value);
void set(T value);
}
public interface GetSetInherited<T> extends GetSet<T> {
/* empty */
}
public static class Swap {
public static void swap(@FieldProxy(FOO) Get<String> getter, @FieldProxy(FOO) Set<String> setter) {
assertThat(getter, not(instanceOf(Serializable.class)));
assertThat(setter, not(instanceOf(Serializable.class)));
setter.set(getter.get() + BAR);
}
}
public static class SwapDuplex {
public static void swap(@FieldProxy(FOO) GetSet<String> accessor) {
assertThat(accessor, not(instanceOf(Serializable.class)));
accessor.set(accessor.get() + BAR);
}
}
public static class Explicit {
protected String foo = FOO;
public void swap() {
/* do nothing */
}
}
public static class ExplicitInherited extends Explicit {
protected String foo = QUX;
@Override
public void swap() {
/* do nothing */
}
}
public static class SwapInherited {
public static void swap(@FieldProxy(value = FOO, declaringType = Explicit.class) Get<String> getter,
@FieldProxy(value = FOO, declaringType = Explicit.class) Set<String> setter) {
assertThat(getter, not(instanceOf(Serializable.class)));
assertThat(setter, not(instanceOf(Serializable.class)));
setter.set(getter.get() + BAR);
}
}
public static class ExplicitStatic {
protected static String foo;
public void swap() {
/* do nothing */
}
}
public static class ImplicitGetter {
protected String foo = FOO;
public String getFoo() {
return null;
}
}
public static class GetInterceptor {
public static String get(@FieldProxy Get<String> getter, @FieldProxy Set<String> setter) {
setter.set(getter.get() + BAR);
return getter.get();
}
}
public static class SetInterceptor {
public static void set(@Argument(0) String value, @FieldProxy Get<String> getter, @FieldProxy Set<String> setter) {
setter.set(getter.get() + value);
}
}
public static class GetInterceptorDuplex {
public static String get(@FieldProxy GetSet<String> accessor) {
accessor.set(accessor.get() + BAR);
return accessor.get();
}
}
public static class SetInterceptorDuplex {
public static void set(@Argument(0) String value, @FieldProxy GetSet<String> accessor) {
accessor.set(accessor.get() + value);
}
}
public static class ImplicitSetter {
protected String foo = FOO;
public void setFoo(String value) {
/* do nothing */
}
}
public static class FinalField {
protected final String foo = FOO;
public void method() {
/* do nothing */
}
}
public static class SwapSerializable {
public static void swap(@FieldProxy(value = FOO, serializableProxy = true) Get<String> getter,
@FieldProxy(value = FOO, serializableProxy = true) Set<String> setter) {
assertThat(getter, instanceOf(Serializable.class));
assertThat(setter, instanceOf(Serializable.class));
setter.set(getter.get() + BAR);
}
}
public static class SwapSerializableDuplex {
public static void swap(@FieldProxy(value = FOO, serializableProxy = true) GetSet<String> accessor) {
assertThat(accessor, instanceOf(Serializable.class));
accessor.set(accessor.get() + BAR);
}
}
public static class GetterIncompatible {
public static void swap(@FieldProxy(FOO) Get<Integer> getter, @FieldProxy(FOO) Set<String> setter) {
Integer value = getter.get();
}
}
public static class SetterIncompatible {
public static void swap(@FieldProxy(FOO) Get<String> getter, @FieldProxy(FOO) Set<Integer> setter) {
setter.set(0);
}
}
public static class GetterIncompatibleDuplex {
public static void swap(@FieldProxy(FOO) GetSet<Integer> accessor) {
Integer value = accessor.get();
}
}
public static class SetterIncompatibleDuplex {
public static void swap(@FieldProxy(FOO) GetSet<Integer> accessor) {
accessor.set(0);
}
}
}