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.FieldValue; import net.bytebuddy.implementation.bind.annotation.RuntimeType; import org.junit.Test; import static net.bytebuddy.matcher.ElementMatchers.isDeclaredBy; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; public class MethodDelegationFieldValueTest { private static final String FOO = "foo", BAR = "bar"; @Test public void testLegalFieldAccess() throws Exception { DynamicType.Loaded<SimpleField> loaded = new ByteBuddy() .subclass(SimpleField.class) .method(isDeclaredBy(SimpleField.class)) .intercept(MethodDelegation.to(SimpleInterceptor.class)) .make() .load(SimpleField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); SimpleField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); instance.foo = FOO; assertThat(instance.foo(), is((Object) FOO)); instance.foo = BAR; assertThat(instance.foo(), is((Object) BAR)); } @Test public void testLegalFieldAccessStatic() throws Exception { DynamicType.Loaded<SimpleStaticField> loaded = new ByteBuddy() .subclass(SimpleStaticField.class) .method(isDeclaredBy(SimpleStaticField.class)) .intercept(MethodDelegation.to(SimpleInterceptor.class)) .make() .load(SimpleStaticField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); SimpleStaticField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); SimpleStaticField.foo = FOO; assertThat(instance.foo(), is((Object) FOO)); SimpleStaticField.foo = BAR; assertThat(instance.foo(), is((Object) BAR)); } @Test(expected = IllegalArgumentException.class) public void testNonAssignableFieldAccess() throws Exception { new ByteBuddy() .subclass(SimpleField.class) .method(isDeclaredBy(SimpleField.class)) .intercept(MethodDelegation.to(NonAssignableInterceptor.class)) .make(); } @Test public void testLegalFieldAccessDynamicTyping() throws Exception { DynamicType.Loaded<SimpleStaticField> loaded = new ByteBuddy() .subclass(SimpleStaticField.class) .method(isDeclaredBy(SimpleStaticField.class)) .intercept(MethodDelegation.to(DynamicInterceptor.class)) .make() .load(SimpleStaticField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); SimpleStaticField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); SimpleStaticField.foo = FOO; assertThat(instance.foo(), is((Object) FOO)); SimpleStaticField.foo = BAR; assertThat(instance.foo(), is((Object) BAR)); } @Test public void testExtendedFieldMostSpecific() throws Exception { DynamicType.Loaded<ExtendedField> loaded = new ByteBuddy() .subclass(ExtendedField.class) .method(isDeclaredBy(ExtendedField.class)) .intercept(MethodDelegation.to(SimpleInterceptor.class)) .make() .load(ExtendedField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); ExtendedField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); instance.foo = FOO; assertThat(instance.foo(), is((Object) FOO)); instance.foo = BAR; assertThat(instance.foo(), is((Object) BAR)); } @Test public void testExtendedFieldSkipsNonVisible() throws Exception { DynamicType.Loaded<ExtendedPrivateField> loaded = new ByteBuddy() .subclass(ExtendedPrivateField.class) .method(isDeclaredBy(ExtendedPrivateField.class)) .intercept(MethodDelegation.to(SimpleInterceptor.class)) .make() .load(ExtendedPrivateField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); SimpleField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); instance.foo = FOO; assertThat(instance.foo(), is((Object) FOO)); instance.foo = BAR; assertThat(instance.foo(), is((Object) BAR)); } @Test public void testExtendedFieldExplicitType() throws Exception { DynamicType.Loaded<ExtendedField> loaded = new ByteBuddy() .subclass(ExtendedField.class) .method(isDeclaredBy(ExtendedField.class)) .intercept(MethodDelegation.to(ExplicitInterceptor.class)) .make() .load(ExtendedField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); SimpleField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); instance.foo = FOO; assertThat(instance.foo(), is((Object) FOO)); instance.foo = BAR; assertThat(instance.foo(), is((Object) BAR)); } @Test public void testAccessor() throws Exception { DynamicType.Loaded<SimpleFieldAccessor> loaded = new ByteBuddy() .subclass(SimpleFieldAccessor.class) .method(isDeclaredBy(SimpleFieldAccessor.class)) .intercept(MethodDelegation.to(SimpleAccessorInterceptor.class)) .make() .load(SimpleFieldAccessor.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); SimpleFieldAccessor instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); instance.foo = FOO; assertThat(instance.getFoo(), is((Object) FOO)); instance.foo = BAR; instance.setFoo(FOO); assertThat(instance.foo, is((Object) BAR)); } public static class SimpleField { public Object foo; public Object foo() { return null; } } public static class SimpleStaticField { public static Object foo; public Object foo() { return null; } } public static class SimpleInterceptor { public static Object intercept(@FieldValue(FOO) Object value) { return value; } } public static class NonAssignableInterceptor { public static Object intercept(@FieldValue(FOO) String value) { return value; } } public static class DynamicInterceptor { public static Object intercept(@RuntimeType @FieldValue(FOO) String value) { return value; } } public static class ExtendedField extends SimpleField { public Object foo; @Override public Object foo() { return null; } } public static class ExtendedPrivateField extends SimpleField { private Object foo; @Override public Object foo() { return null; } } public static class ExplicitInterceptor { public static Object intercept(@FieldValue(value = FOO, declaringType = SimpleField.class) Object value) { return value; } } public static class SimpleFieldAccessor { public Object foo; public Object getFoo() { return foo; } public void setFoo(Object foo) { this.foo = foo; } } public static class SimpleAccessorInterceptor { public static Object intercept(@FieldValue Object value) { return value; } } }