package net.bytebuddy.implementation; import net.bytebuddy.ByteBuddy; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.test.utility.CallTraceable; import net.bytebuddy.test.utility.JavaVersionRule; import net.bytebuddy.test.utility.ObjectPropertyAssertion; import net.bytebuddy.utility.JavaConstant; import net.bytebuddy.utility.JavaType; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.MethodRule; import java.util.Arrays; import java.util.Iterator; 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 FixedValueTest { private static final String BAR = "bar"; @Rule public MethodRule javaVersionRule = new JavaVersionRule(); private Bar bar; private static Object makeMethodType(Class<?> returnType, Class<?>... parameterType) throws Exception { return JavaType.METHOD_TYPE.load().getDeclaredMethod("methodType", Class.class, Class[].class).invoke(null, returnType, parameterType); } private static Object makeMethodHandle() throws Exception { Object lookup = Class.forName("java.lang.invoke.MethodHandles").getDeclaredMethod("publicLookup").invoke(null); return JavaType.METHOD_HANDLES_LOOKUP.load().getDeclaredMethod("findVirtual", Class.class, String.class, JavaType.METHOD_TYPE.load()) .invoke(lookup, Qux.class, BAR, makeMethodType(Object.class)); } @Before public void setUp() throws Exception { bar = new Bar(); } @Test public void testTypeDescriptionConstantPool() throws Exception { Class<? extends Qux> qux = new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.value(TypeDescription.OBJECT)) .make() .load(Qux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(qux.getDeclaredFields().length, is(0)); assertThat(qux.getDeclaredConstructor().newInstance().bar(), is((Object) Object.class)); } @Test public void testClassConstantPool() throws Exception { Class<? extends Qux> qux = new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.value(Object.class)) .make() .load(Qux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(qux.getDeclaredFields().length, is(0)); assertThat(qux.getDeclaredConstructor().newInstance().bar(), is((Object) Object.class)); } @Test @JavaVersionRule.Enforce(7) public void testMethodTypeConstantPool() throws Exception { Class<? extends Qux> qux = new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.value(JavaConstant.MethodType.of(void.class, Object.class))) .make() .load(Qux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(qux.getDeclaredFields().length, is(0)); assertThat(qux.getDeclaredConstructor().newInstance().bar(), is(makeMethodType(void.class, Object.class))); } @Test @JavaVersionRule.Enforce(7) public void testMethodTypeConstantPoolValue() throws Exception { Class<? extends Qux> qux = new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.value(makeMethodType(void.class, Object.class))) .make() .load(Qux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(qux.getDeclaredFields().length, is(0)); assertThat(qux.getDeclaredConstructor().newInstance().bar(), is(makeMethodType(void.class, Object.class))); } @Test @JavaVersionRule.Enforce(value = 7, hotSpot = 7) public void testMethodHandleConstantPool() throws Exception { Class<? extends Qux> qux = new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.value(JavaConstant.MethodHandle.of(Qux.class.getDeclaredMethod("bar")))) .make() .load(Qux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(qux.getDeclaredFields().length, is(0)); assertThat(JavaConstant.MethodHandle.ofLoaded(qux.getDeclaredConstructor().newInstance().bar()), is(JavaConstant.MethodHandle.ofLoaded(makeMethodHandle()))); } @Test @JavaVersionRule.Enforce(value = 7, hotSpot = 7) public void testMethodHandleConstantPoolValue() throws Exception { Class<? extends Qux> qux = new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.value(makeMethodHandle())) .make() .load(Qux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(qux.getDeclaredFields().length, is(0)); assertThat(JavaConstant.MethodHandle.ofLoaded(qux.getDeclaredConstructor().newInstance().bar()), is(JavaConstant.MethodHandle.ofLoaded(makeMethodHandle()))); } @Test public void testReferenceCall() throws Exception { new ByteBuddy() .subclass(Qux.class) .method(isDeclaredBy(Qux.class)) .intercept(FixedValue.reference(bar)) .make(); } @Test public void testValueCall() throws Exception { new ByteBuddy() .subclass(Foo.class) .method(isDeclaredBy(Foo.class)) .intercept(FixedValue.reference(bar)) .make(); } @Test public void testNullValue() throws Exception { Class<? extends Foo> foo = new ByteBuddy() .subclass(Foo.class) .method(isDeclaredBy(Foo.class)) .intercept(FixedValue.nullValue()) .make() .load(Foo.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(foo.getDeclaredFields().length, is(0)); assertThat(foo.getDeclaredMethods().length, is(1)); assertThat(foo.getDeclaredMethod(BAR).invoke(foo.getDeclaredConstructor().newInstance()), nullValue(Object.class)); } @Test(expected = IllegalStateException.class) public void testNullValueNonAssignable() throws Exception { new ByteBuddy() .subclass(FooBar.class) .method(isDeclaredBy(FooBar.class)) .intercept(FixedValue.nullValue()) .make(); } @Test public void testThisValue() throws Exception { Class<? extends QuxBaz> quxbaz = new ByteBuddy() .subclass(QuxBaz.class) .method(isDeclaredBy(QuxBaz.class)) .intercept(FixedValue.self()) .make() .load(QuxBaz.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(quxbaz.getDeclaredFields().length, is(0)); assertThat(quxbaz.getDeclaredMethods().length, is(1)); QuxBaz self = quxbaz.getDeclaredConstructor().newInstance(); assertThat(self.bar(), sameInstance((Object) self)); } @Test(expected = IllegalStateException.class) public void testThisValueStatic() throws Exception { new ByteBuddy() .redefine(FooBarQuxBaz.class) .method(named("bar")) .intercept(FixedValue.self()) .make(); } @Test(expected = IllegalStateException.class) public void testThisValueNonAssignable() throws Exception { new ByteBuddy() .subclass(Foo.class) .method(isDeclaredBy(Foo.class)) .intercept(FixedValue.self()) .make(); } @Test public void testOriginType() throws Exception { Class<? extends Baz> baz = new ByteBuddy() .subclass(Baz.class) .method(isDeclaredBy(Baz.class)) .intercept(FixedValue.originType()) .make() .load(QuxBaz.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(baz.getDeclaredFields().length, is(0)); assertThat(baz.getDeclaredMethods().length, is(1)); assertThat(baz.getDeclaredMethod(BAR).invoke(baz.getDeclaredConstructor().newInstance()), is((Object) Baz.class)); } @Test public void testArgument() throws Exception { Class<? extends FooQux> fooQux = new ByteBuddy() .subclass(FooQux.class) .method(isDeclaredBy(FooQux.class)) .intercept(FixedValue.argument(1)) .make() .load(FooQux.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER) .getLoaded(); assertThat(fooQux.getDeclaredFields().length, is(0)); assertThat(fooQux.getDeclaredMethods().length, is(1)); assertThat(fooQux.getDeclaredMethod(BAR, Integer.class, String.class) .invoke(fooQux.getDeclaredConstructor().newInstance(), 0, BAR), is((Object) BAR)); } @Test(expected = IllegalArgumentException.class) public void testArgumentNegative() throws Exception { FixedValue.argument(-1); } @Test(expected = IllegalStateException.class) public void testArgumentNotAssignable() throws Exception { new ByteBuddy() .subclass(FooQux.class) .method(isDeclaredBy(FooQux.class)) .intercept(FixedValue.argument(0)) .make(); } @Test(expected = IllegalStateException.class) public void testArgumentNonExistent() throws Exception { new ByteBuddy() .subclass(FooQux.class) .method(isDeclaredBy(FooQux.class)) .intercept(FixedValue.argument(2)) .make(); } @Test public void testObjectProperties() throws Exception { final Iterator<Class<?>> iterator = Arrays.<Class<?>>asList(Object.class, String.class, Integer.class).iterator(); ObjectPropertyAssertion.of(FixedValue.ForPoolValue.class).create(new ObjectPropertyAssertion.Creator<Class<?>>() { @Override public Class<?> create() { return iterator.next(); } }).skipSynthetic().apply(); ObjectPropertyAssertion.of(FixedValue.ForValue.class).apply(); ObjectPropertyAssertion.of(FixedValue.ForOriginType.class).apply(); ObjectPropertyAssertion.of(FixedValue.ForOriginType.Appender.class).apply(); ObjectPropertyAssertion.of(FixedValue.ForNullValue.class).apply(); ObjectPropertyAssertion.of(FixedValue.ForThisValue.class).apply(); ObjectPropertyAssertion.of(FixedValue.ForThisValue.Appender.class).apply(); ObjectPropertyAssertion.of(FixedValue.ForArgument.class).apply(); } public static class Foo extends CallTraceable { public Bar bar() { register(BAR); return new Bar(); } } public static class Bar { /* empty */ } public static class Qux extends CallTraceable { public Object bar() { register(BAR); return null; } } public static class Baz { public Class<?> bar() { return null; } } public static class FooBar { public void bar() { /* empty */ } } public static class QuxBaz { public Object bar() { return null; } } public static class FooBarQuxBaz { public static Object bar() { return null; } } public static class FooQux { public String bar(Integer arg0, String arg1) { return null; } } }