package net.bytebuddy.implementation; import net.bytebuddy.ByteBuddy; import net.bytebuddy.description.method.MethodDescription; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.dynamic.loading.ClassLoadingStrategy; import net.bytebuddy.implementation.bytecode.StackManipulation; import net.bytebuddy.implementation.bytecode.assign.Assigner; import net.bytebuddy.implementation.bytecode.constant.TextConstant; import net.bytebuddy.implementation.bytecode.member.MethodReturn; import net.bytebuddy.matcher.ElementMatchers; import net.bytebuddy.test.utility.*; import net.bytebuddy.utility.JavaConstant; import net.bytebuddy.utility.JavaType; import org.hamcrest.CoreMatchers; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.MethodRule; import org.junit.rules.TestRule; import org.mockito.Mock; import org.mockito.Mockito; import java.lang.reflect.Method; import java.util.Arrays; import java.util.Iterator; import java.util.concurrent.Callable; import static net.bytebuddy.matcher.ElementMatchers.*; import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.MatcherAssert.assertThat; import static org.mockito.Mockito.*; public class MethodCallTest { private static final String FOO = "foo", BAR = "bar", INVOKE_FOO = "invokeFoo"; private static final String SINGLE_DEFAULT_METHOD = "net.bytebuddy.test.precompiled.SingleDefaultMethodInterface"; @Rule public TestRule methodRule = new MockitoRule(this); @Rule public MethodRule javaVersionRule = new JavaVersionRule(); @Mock private Assigner nonAssigner; 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("findStatic", Class.class, String.class, JavaType.METHOD_TYPE.load()) .invoke(lookup, Foo.class, BAR, makeMethodType(String.class, Object.class, Object.class)); } @Before public void setUp() throws Exception { when(nonAssigner.assign(Mockito.any(TypeDescription.Generic.class), Mockito.any(TypeDescription.Generic.class), Mockito.any(Assigner.Typing.class))).thenReturn(StackManipulation.Illegal.INSTANCE); } @Test public void testStaticMethodInvocationWithoutArguments() throws Exception { DynamicType.Loaded<SimpleMethod> loaded = new ByteBuddy() .subclass(SimpleMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(SimpleMethod.class.getDeclaredMethod(BAR))) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SimpleMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is(BAR)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SimpleMethod.class))); assertThat(instance, instanceOf(SimpleMethod.class)); } @Test public void testExternalStaticMethodInvocationWithoutArguments() throws Exception { DynamicType.Loaded<SimpleMethod> loaded = new ByteBuddy() .subclass(SimpleMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(StaticExternalMethod.class.getDeclaredMethod(BAR))) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SimpleMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is(BAR)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SimpleMethod.class))); assertThat(instance, instanceOf(SimpleMethod.class)); } @Test public void testInstanceMethodInvocationWithoutArguments() throws Exception { DynamicType.Loaded<InstanceMethod> loaded = new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(InstanceMethod.class.getDeclaredMethod(BAR))) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); InstanceMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is(BAR)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(InstanceMethod.class))); assertThat(instance, instanceOf(InstanceMethod.class)); } @Test public void testInstanceMethodInvocationWithoutArgumentsByMatcher() throws Exception { DynamicType.Loaded<InstanceMethod> loaded = new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(named(BAR))) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); InstanceMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is(BAR)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(InstanceMethod.class))); assertThat(instance, instanceOf(InstanceMethod.class)); } @Test(expected = IllegalStateException.class) public void testMatchedCallAmbiguous() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(ElementMatchers.any())) .make(); } @Test(expected = IllegalArgumentException.class) public void testOnArgumentInvocationNegativeArgument() throws Exception { MethodCall.invoke(Object.class.getDeclaredMethod("toString")).onArgument(-1); } @Test(expected = IllegalArgumentException.class) public void testOnArgumentInvocationNonExisting() throws Exception { new ByteBuddy() .subclass(ArgumentCall.class) .method(isDeclaredBy(ArgumentCall.class)) .intercept(MethodCall.invoke(Object.class.getDeclaredMethod("toString")).onArgument(10)) .make(); } @Test public void testInvokeOnArgument() throws Exception { DynamicType.Loaded<ArgumentCall> loaded = new ByteBuddy() .subclass(ArgumentCall.class) .method(isDeclaredBy(ArgumentCall.class)) .intercept(MethodCall.invoke(ArgumentCall.Target.class.getDeclaredMethod("foo")).onArgument(0)) .make() .load(ArgumentCall.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); ArgumentCall instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(new ArgumentCall.Target(BAR)), is(BAR)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(InstanceMethod.class))); assertThat(instance, instanceOf(ArgumentCall.class)); } @Test(expected = IllegalStateException.class) public void testInvokeOnArgumentNonAssignable() throws Exception { new ByteBuddy() .subclass(ArgumentCallDynamic.class) .method(isDeclaredBy(ArgumentCallDynamic.class)) .intercept(MethodCall.invoke(ArgumentCallDynamic.Target.class.getDeclaredMethod("foo")).onArgument(0)) .make(); } @Test(expected = IllegalStateException.class) public void testInvokeOnArgumentNonVirtual() throws Exception { new ByteBuddy() .subclass(ArgumentCallDynamic.class) .method(isDeclaredBy(ArgumentCallDynamic.class)) .intercept(MethodCall.invoke(NonVirtual.class.getDeclaredMethod("foo")).onArgument(0)) .make(); } @Test public void testInvokeOnArgumentDynamic() throws Exception { DynamicType.Loaded<ArgumentCallDynamic> loaded = new ByteBuddy() .subclass(ArgumentCallDynamic.class) .method(isDeclaredBy(ArgumentCallDynamic.class)) .intercept(MethodCall.invoke(ArgumentCallDynamic.Target.class.getDeclaredMethod("foo")).onArgument(0) .withAssigner(Assigner.DEFAULT, Assigner.Typing.DYNAMIC)) .make() .load(ArgumentCallDynamic.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); ArgumentCallDynamic instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(new ArgumentCallDynamic.Target(BAR)), is(BAR)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(InstanceMethod.class))); assertThat(instance, instanceOf(ArgumentCallDynamic.class)); } @Test public void testSuperConstructorInvocationWithoutArguments() throws Exception { DynamicType.Loaded<Object> loaded = new ByteBuddy() .subclass(Object.class) .constructor(ElementMatchers.any()) .intercept(MethodCall.invoke(Object.class.getDeclaredConstructor()).onSuper()) .make() .load(Object.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(0)); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); Object instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(Object.class))); assertThat(instance, instanceOf(Object.class)); } @Test public void testObjectConstruction() throws Exception { DynamicType.Loaded<SelfReference> loaded = new ByteBuddy() .subclass(SelfReference.class) .method(isDeclaredBy(SelfReference.class)) .intercept(MethodCall.construct(SelfReference.class.getDeclaredConstructor())) .make() .load(SelfReference.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SelfReference instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); SelfReference created = instance.foo(); assertThat(created.getClass(), CoreMatchers.<Class<?>>is(SelfReference.class)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SelfReference.class))); assertThat(instance, instanceOf(SelfReference.class)); assertThat(created, not(instance)); } @Test public void testSelfInvocation() throws Exception { SuperMethodInvocation delegate = mock(SuperMethodInvocation.class); when(delegate.foo()).thenReturn(FOO); DynamicType.Loaded<SuperMethodInvocation> loaded = new ByteBuddy() .subclass(SuperMethodInvocation.class) .method(takesArguments(0).and(named(FOO))) .intercept(MethodCall.invokeSelf().on(delegate)) .make() .load(SuperMethodInvocation.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(1)); SuperMethodInvocation instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SuperMethodInvocation.class))); assertThat(instance, instanceOf(SuperMethodInvocation.class)); assertThat(instance.foo(), is(FOO)); verify(delegate).foo(); verifyNoMoreInteractions(delegate); } @Test public void testSuperInvocation() throws Exception { DynamicType.Loaded<SuperMethodInvocation> loaded = new ByteBuddy() .subclass(SuperMethodInvocation.class) .method(takesArguments(0).and(named(FOO))) .intercept(MethodCall.invokeSuper()) .make() .load(SuperMethodInvocation.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SuperMethodInvocation instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SuperMethodInvocation.class))); assertThat(instance, instanceOf(SuperMethodInvocation.class)); assertThat(instance.foo(), is(FOO)); } @Test public void testWithExplicitArgumentConstantPool() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().with(FOO)) .make() .load(MethodCallWithExplicitArgument.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithExplicitArgument instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallWithExplicitArgument.class)); assertThat(instance.foo(BAR), is(FOO)); } @Test(expected = IllegalStateException.class) public void testWithExplicitArgumentConstantPoolNonAssignable() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().with(FOO).withAssigner(nonAssigner, Assigner.Typing.STATIC)) .make(); } @Test public void testWithExplicitArgumentStackManipulation() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().with(new TextConstant(FOO), String.class)) .make() .load(MethodCallWithExplicitArgument.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithExplicitArgument instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallWithExplicitArgument.class)); assertThat(instance.foo(BAR), is(FOO)); } @Test public void testWithExplicitArgumentField() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().withReference(FOO)) .make() .load(MethodCallWithExplicitArgument.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(1)); MethodCallWithExplicitArgument instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallWithExplicitArgument.class)); assertThat(instance.foo(BAR), is(FOO)); } @Test(expected = IllegalStateException.class) public void testWithExplicitArgumentFieldNonAssignable() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().withReference(FOO).withAssigner(nonAssigner, Assigner.Typing.STATIC)) .make(); } @Test public void testWithArgument() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().withArgument(0)) .make() .load(MethodCallWithExplicitArgument.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithExplicitArgument instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallWithExplicitArgument.class)); assertThat(instance.foo(BAR), is(BAR)); } @Test public void testWithAllArguments() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().withAllArguments()) .make() .load(MethodCallWithExplicitArgument.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithExplicitArgument instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallWithExplicitArgument.class)); assertThat(instance.foo(BAR), is(BAR)); } @Test public void testWithAllArgumentsTwoArguments() throws Exception { DynamicType.Loaded<MethodCallWithTwoExplicitArguments> loaded = new ByteBuddy() .subclass(MethodCallWithTwoExplicitArguments.class) .method(isDeclaredBy(MethodCallWithTwoExplicitArguments.class)) .intercept(MethodCall.invokeSuper().withAllArguments()) .make() .load(MethodCallWithTwoExplicitArguments.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithTwoExplicitArguments instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithTwoExplicitArguments.class))); assertThat(instance, instanceOf(MethodCallWithTwoExplicitArguments.class)); assertThat(instance.foo(FOO, BAR), is(FOO + BAR)); } @Test public void testWithArgumentsAsArray() throws Exception { DynamicType.Loaded<ArrayConsuming> loaded = new ByteBuddy() .subclass(ArrayConsuming.class) .method(named(FOO)) .intercept(MethodCall.invoke(ArrayConsuming.class.getDeclaredMethod(BAR, String[].class)).withArgumentArray()) .make() .load(ArrayConsuming.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); ArrayConsuming instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(ArrayConsuming.class))); assertThat(instance, instanceOf(ArrayConsuming.class)); assertThat(instance.foo(FOO, BAR), is(FOO + BAR)); } @Test public void testWithArgumentsFromArray() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(MethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0, 1)) .make() .load(MethodCallDelegator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(INVOKE_FOO, String[].class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallDelegator instance = (MethodCallDelegator) loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallDelegator.class)); assertThat(instance.invokeFoo(BAR), is(BAR)); } @Test public void testWithArgumentsFromArrayComplete() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(MethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0)) .make() .load(MethodCallDelegator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(INVOKE_FOO, String[].class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallDelegator instance = (MethodCallDelegator) loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallDelegator.class)); assertThat(instance.invokeFoo(BAR), is(BAR)); } @Test public void testWithArgumentsFromArrayExplicitSize() throws Exception { DynamicType.Loaded<MethodCallWithExplicitArgument> loaded = new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(MethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0, 1, 1)) .make() .load(MethodCallDelegator.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(INVOKE_FOO, String[].class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallDelegator instance = (MethodCallDelegator) loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithExplicitArgument.class))); assertThat(instance, instanceOf(MethodCallDelegator.class)); assertThat(instance.invokeFoo(FOO, BAR, FOO), is(BAR)); } @Test(expected = IllegalStateException.class) public void testWithArgumentsFromArrayDoesNotExist() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(MethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(1, 1)) .make(); } @Test(expected = IllegalStateException.class) public void testWithArgumentsFromArrayDoesNotExistCompleteArray() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(MethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(1)) .make(); } @Test(expected = IllegalStateException.class) public void testWithArgumentsFromArrayIllegalType() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(IllegalMethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0, 1)) .make(); } @Test(expected = IllegalStateException.class) public void testWithArgumentsFromArrayIllegalTypeCompleteArray() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .implement(IllegalMethodCallDelegator.class) .intercept(MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0)) .make(); } @Test(expected = IllegalArgumentException.class) public void testNegativeIndex() throws Exception { MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(-1, 1); } @Test(expected = IllegalArgumentException.class) public void testNegativeIndexComplete() throws Exception { MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(-1); } @Test(expected = IllegalArgumentException.class) public void testNegativeStartIndex() throws Exception { MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0, -1, 1); } @Test(expected = IllegalArgumentException.class) public void testNegativeSize() throws Exception { MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)).withArgumentArrayElements(0, 1, -1); } @Test public void testSameSize() throws Exception { MethodCall methodCall = MethodCall.invoke(MethodCallWithExplicitArgument.class.getDeclaredMethod("foo", String.class)); assertThat(methodCall.withArgumentArrayElements(0, 0), sameInstance(methodCall)); } @Test(expected = IllegalStateException.class) public void testWithTooBigParameter() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().withArgument(1)) .make(); } @Test(expected = IllegalStateException.class) public void testWithParameterNonAssignable() throws Exception { new ByteBuddy() .subclass(MethodCallWithExplicitArgument.class) .method(isDeclaredBy(MethodCallWithExplicitArgument.class)) .intercept(MethodCall.invokeSuper().withArgument(0).withAssigner(nonAssigner, Assigner.Typing.STATIC)) .make(); } @Test public void testWithField() throws Exception { DynamicType.Loaded<MethodCallWithField> loaded = new ByteBuddy() .subclass(MethodCallWithField.class) .method(isDeclaredBy(MethodCallWithField.class)) .intercept(MethodCall.invokeSuper().withField(FOO)) .make() .load(MethodCallWithField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); instance.foo = FOO; assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithField.class))); assertThat(instance, instanceOf(MethodCallWithField.class)); assertThat(instance.foo(BAR), is(FOO)); } @Test(expected = IllegalStateException.class) public void testWithFieldNotExist() throws Exception { new ByteBuddy() .subclass(MethodCallWithField.class) .method(isDeclaredBy(MethodCallWithField.class)) .intercept(MethodCall.invokeSuper().withField(BAR)) .make(); } @Test(expected = IllegalStateException.class) public void testWithFieldNonAssignable() throws Exception { new ByteBuddy() .subclass(MethodCallWithField.class) .method(isDeclaredBy(MethodCallWithField.class)) .intercept(MethodCall.invokeSuper().withField(FOO).withAssigner(nonAssigner, Assigner.Typing.STATIC)) .make(); } @Test public void testWithFieldHierarchyVisibility() throws Exception { DynamicType.Loaded<InvisibleMethodCallWithField> loaded = new ByteBuddy() .subclass(InvisibleMethodCallWithField.class) .method(isDeclaredBy(InvisibleMethodCallWithField.class)) .intercept(MethodCall.invokeSuper().withField(FOO)) .make() .load(InvisibleMethodCallWithField.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, String.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); InvisibleMethodCallWithField instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); ((InvisibleBase) instance).foo = FOO; assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(InvisibleMethodCallWithField.class))); assertThat(instance, instanceOf(InvisibleMethodCallWithField.class)); assertThat(instance.foo(BAR), is(FOO)); } @Test public void testWithThis() throws Exception { DynamicType.Loaded<MethodCallWithThis> loaded = new ByteBuddy() .subclass(MethodCallWithThis.class) .method(isDeclaredBy(MethodCallWithThis.class)) .intercept(MethodCall.invokeSuper().withThis()) .make() .load(MethodCallWithThis.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, MethodCallWithThis.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithThis instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithThis.class))); assertThat(instance, instanceOf(MethodCallWithThis.class)); assertThat(instance.foo(null), is(instance)); } @Test public void testWithOwnType() throws Exception { DynamicType.Loaded<MethodCallWithOwnType> loaded = new ByteBuddy() .subclass(MethodCallWithOwnType.class) .method(isDeclaredBy(MethodCallWithOwnType.class)) .intercept(MethodCall.invokeSuper().withOwnType()) .make() .load(MethodCallWithOwnType.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO, Class.class), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallWithOwnType instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallWithThis.class))); assertThat(instance, instanceOf(MethodCallWithOwnType.class)); assertThat(instance.foo(null), CoreMatchers.<Class<?>>is(loaded.getLoaded())); } @Test public void testImplementationAppendingMethod() throws Exception { DynamicType.Loaded<MethodCallAppending> loaded = new ByteBuddy() .subclass(MethodCallAppending.class) .method(isDeclaredBy(MethodCallAppending.class)) .intercept(MethodCall.invokeSuper().andThen(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE))) .make() .load(MethodCallAppending.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallAppending instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallAppending.class))); assertThat(instance, instanceOf(MethodCallAppending.class)); assertThat(instance.foo(), is((Object) FOO)); instance.assertOnlyCall(FOO); } @Test public void testImplementationAppendingConstructor() throws Exception { DynamicType.Loaded<MethodCallAppending> loaded = new ByteBuddy() .subclass(MethodCallAppending.class) .method(isDeclaredBy(MethodCallAppending.class)) .intercept(MethodCall.construct(Object.class.getDeclaredConstructor()) .andThen(new Implementation.Simple(new TextConstant(FOO), MethodReturn.REFERENCE))) .make() .load(MethodCallAppending.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); MethodCallAppending instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(MethodCallAppending.class))); assertThat(instance, instanceOf(MethodCallAppending.class)); assertThat(instance.foo(), is((Object) FOO)); instance.assertZeroCalls(); } @Test public void testWithExplicitTarget() throws Exception { Object target = new Object(); DynamicType.Loaded<ExplicitTarget> loaded = new ByteBuddy() .subclass(ExplicitTarget.class) .method(isDeclaredBy(ExplicitTarget.class)) .intercept(MethodCall.invoke(Object.class.getDeclaredMethod("toString")).on(target)) .make() .load(ExplicitTarget.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(1)); ExplicitTarget instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(ExplicitTarget.class))); assertThat(instance, instanceOf(ExplicitTarget.class)); assertThat(instance.foo(), is(target.toString())); } @Test public void testWithFieldTarget() throws Exception { Object target = new Object(); DynamicType.Loaded<ExplicitTarget> loaded = new ByteBuddy() .subclass(ExplicitTarget.class) .defineField(FOO, Object.class, Visibility.PUBLIC) .method(isDeclaredBy(ExplicitTarget.class)) .intercept(MethodCall.invoke(Object.class.getDeclaredMethod("toString")).onField(FOO)) .make() .load(ExplicitTarget.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredMethod(FOO), not(nullValue(Method.class))); assertThat(loaded.getLoaded().getDeclaredConstructors().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(1)); ExplicitTarget instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); loaded.getLoaded().getDeclaredField(FOO).set(instance, target); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(ExplicitTarget.class))); assertThat(instance, instanceOf(ExplicitTarget.class)); assertThat(instance.foo(), is(target.toString())); } @Test public void testUnloadedType() throws Exception { DynamicType.Loaded<SimpleMethod> loaded = new ByteBuddy() .subclass(SimpleMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(Foo.class.getDeclaredMethod(BAR, Object.class, Object.class)).with(TypeDescription.OBJECT, TypeDescription.STRING)) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SimpleMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is("" + Object.class + String.class)); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SimpleMethod.class))); assertThat(instance, instanceOf(SimpleMethod.class)); } @Test @JavaVersionRule.Enforce(value = 7, hotSpot = 7) public void testJava7Types() throws Exception { DynamicType.Loaded<SimpleMethod> loaded = new ByteBuddy() .subclass(SimpleMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(Foo.class.getDeclaredMethod(BAR, Object.class, Object.class)).with(makeMethodHandle(), makeMethodType(void.class))) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SimpleMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is("" + makeMethodHandle() + makeMethodType(void.class))); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SimpleMethod.class))); assertThat(instance, instanceOf(SimpleMethod.class)); } @Test @JavaVersionRule.Enforce(value = 7, hotSpot = 7) public void testJava7TypesExplicit() throws Exception { DynamicType.Loaded<SimpleMethod> loaded = new ByteBuddy() .subclass(SimpleMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(Foo.class.getDeclaredMethod(BAR, Object.class, Object.class)) .with(JavaConstant.MethodHandle.ofLoaded(makeMethodHandle()), JavaConstant.MethodType.ofLoaded(makeMethodType(void.class)))) .make() .load(SimpleMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoadedAuxiliaryTypes().size(), is(0)); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); assertThat(loaded.getLoaded().getDeclaredFields().length, is(0)); SimpleMethod instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(instance.foo(), is("" + makeMethodHandle() + makeMethodType(void.class))); assertThat(instance.getClass(), not(CoreMatchers.<Class<?>>is(SimpleMethod.class))); assertThat(instance, instanceOf(SimpleMethod.class)); } @Test @JavaVersionRule.Enforce(8) public void testDefaultMethod() throws Exception { DynamicType.Loaded<Object> loaded = new ByteBuddy() .subclass(Object.class) .implement(Class.forName(SINGLE_DEFAULT_METHOD)) .method(ElementMatchers.not(isDeclaredBy(Object.class))) .intercept(MethodCall.invoke(Class.forName(SINGLE_DEFAULT_METHOD).getDeclaredMethod(FOO)).onDefault()) .make() .load(Class.forName(SINGLE_DEFAULT_METHOD).getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoaded().getDeclaredMethods().length, is(1)); Method method = loaded.getLoaded().getDeclaredMethod(FOO); Object instance = loaded.getLoaded().getDeclaredConstructor().newInstance(); assertThat(method.invoke(instance), is((Object) FOO)); } @Test public void testCallable() throws Exception { Traceable traceable = new Traceable(); DynamicType.Loaded<SimpleStringMethod> loaded = new ByteBuddy() .subclass(SimpleStringMethod.class) .method(isDeclaredBy(SimpleStringMethod.class)) .intercept(MethodCall.call(traceable)) .make() .load(SimpleStringMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoaded().getDeclaredConstructor().newInstance().foo(), is(FOO)); traceable.assertOnlyCall(FOO); } @Test public void testRunnable() throws Exception { Traceable traceable = new Traceable(); DynamicType.Loaded<SimpleStringMethod> loaded = new ByteBuddy() .subclass(SimpleStringMethod.class) .method(isDeclaredBy(SimpleStringMethod.class)) .intercept(MethodCall.run(traceable)) .make() .load(SimpleStringMethod.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER); assertThat(loaded.getLoaded().getDeclaredConstructor().newInstance().foo(), nullValue(String.class)); traceable.assertOnlyCall(FOO); } @Test(expected = IllegalStateException.class) public void testDefaultMethodNotCompatible() throws Exception { new ByteBuddy() .subclass(Object.class) .method(isDeclaredBy(Object.class)) .intercept(MethodCall.invoke(String.class.getDeclaredMethod("toString")).onDefault()) .make(); } @Test(expected = IllegalStateException.class) public void testMethodTypeIncompatible() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(isDeclaredBy(InstanceMethod.class)) .intercept(MethodCall.invoke(String.class.getDeclaredMethod("toLowerCase"))) .make(); } @Test(expected = IllegalStateException.class) public void testArgumentIncompatibleTooFew() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(StaticIncompatibleExternalMethod.class.getDeclaredMethod("bar", String.class))) .make(); } @Test(expected = IllegalStateException.class) public void testArgumentIncompatibleTooMany() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(StaticIncompatibleExternalMethod.class.getDeclaredMethod("bar", String.class)).with(FOO, BAR)) .make(); } @Test(expected = IllegalStateException.class) public void testArgumentIncompatibleNotAssignable() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(StaticIncompatibleExternalMethod.class.getDeclaredMethod("bar", String.class)).with(new Object())) .make(); } @Test(expected = IllegalArgumentException.class) public void testConstructNonConstructorThrowsException() throws Exception { MethodCall.construct(mock(MethodDescription.class)); } @Test(expected = IllegalArgumentException.class) public void testIllegalIndex() throws Exception { MethodCall.invokeSuper().withArgument(-1); } @Test(expected = IllegalStateException.class) public void testMethodCallNonVirtual() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(StaticIncompatibleExternalMethod.class.getDeclaredMethod("bar", String.class)).on(new StaticIncompatibleExternalMethod()).with(FOO)) .make(); } @Test(expected = IllegalStateException.class) public void testMethodCallIncompatibleInstance() throws Exception { new ByteBuddy() .subclass(InstanceMethod.class) .method(named(FOO)) .intercept(MethodCall.invoke(StaticIncompatibleExternalMethod.class.getDeclaredMethod("bar", String.class)).on(new Object()).with(FOO)) .make(); } @Test(expected = IllegalStateException.class) public void testMethodCallNonVisibleType() throws Exception { new ByteBuddy() .subclass(Object.class) .method(isDeclaredBy(Object.class)) .intercept(MethodCall.invoke(PackagePrivateType.class.getDeclaredMethod("foo")).on(new PackagePrivateType())) .make(); } @Test(expected = IllegalStateException.class) public void testMethodCallStaticTargetNonVisibleType() throws Exception { new ByteBuddy() .subclass(Object.class) .method(isDeclaredBy(Object.class)) .intercept(MethodCall.invoke(PackagePrivateType.class.getDeclaredMethod("bar"))) .make(); } @Test(expected = IllegalStateException.class) public void testMethodCallSuperCallNonInvokable() throws Exception { new ByteBuddy() .subclass(Object.class) .method(isDeclaredBy(Object.class)) .intercept(MethodCall.invoke(Bar.class.getDeclaredMethod("bar")).onSuper()) .make(); } @Test(expected = IllegalStateException.class) public void testMethodCallDefaultCallNonInvokable() throws Exception { new ByteBuddy() .subclass(Object.class) .method(isDeclaredBy(Object.class)) .intercept(MethodCall.invoke(Bar.class.getDeclaredMethod("bar")).onDefault()) .make(); } @Test(expected = IllegalStateException.class) public void testMethodCallFieldDoesNotExist() throws Exception { new ByteBuddy() .subclass(ExplicitTarget.class) .method(isDeclaredBy(ExplicitTarget.class)) .intercept(MethodCall.invoke(Object.class.getDeclaredMethod("toString")).onField(FOO)) .make(); } @Test public void testObjectProperties() throws Exception { ObjectPropertyAssertion.of(MethodCall.class).apply(); ObjectPropertyAssertion.of(MethodCall.WithoutSpecifiedTarget.class).apply(); ObjectPropertyAssertion.of(MethodCall.Appender.class).apply(); ObjectPropertyAssertion.of(MethodCall.MethodLocator.ForExplicitMethod.class).apply(); ObjectPropertyAssertion.of(MethodCall.MethodLocator.ForInstrumentedMethod.class).apply(); ObjectPropertyAssertion.of(MethodCall.MethodLocator.ForElementMatcher.class).apply(); ObjectPropertyAssertion.of(MethodCall.MethodInvoker.ForContextualInvocation.class).apply(); final Iterator<Class<?>> iterator = Arrays.<Class<?>>asList(String.class, Object.class).iterator(); ObjectPropertyAssertion.of(MethodCall.MethodInvoker.ForVirtualInvocation.class).create(new ObjectPropertyAssertion.Creator<Class<?>>() { @Override public Class<?> create() { return iterator.next(); } }).apply(); ObjectPropertyAssertion.of(MethodCall.MethodInvoker.ForVirtualInvocation.WithImplicitType.class).apply(); ObjectPropertyAssertion.of(MethodCall.MethodInvoker.ForSuperMethodInvocation.class).apply(); ObjectPropertyAssertion.of(MethodCall.MethodInvoker.ForDefaultMethodInvocation.class).apply(); ObjectPropertyAssertion.of(MethodCall.TerminationHandler.class).apply(); ObjectPropertyAssertion.of(MethodCall.TargetHandler.ForValue.class).apply(); ObjectPropertyAssertion.of(MethodCall.TargetHandler.ForField.class).apply(); ObjectPropertyAssertion.of(MethodCall.TargetHandler.ForSelfOrStaticInvocation.class).apply(); ObjectPropertyAssertion.of(MethodCall.TargetHandler.ForConstructingInvocation.class).apply(); ObjectPropertyAssertion.of(MethodCall.TargetHandler.ForMethodParameter.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForNullConstant.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForThisReference.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForThisReference.Factory.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForInstrumentedType.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForInstrumentedType.Factory.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForInstance.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForInstance.Factory.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForField.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForField.Factory.class).apply(); // ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForStackManipulation.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameter.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameter.Factory.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameter.OfInstrumentedMethod.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameterArray.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameterArray.Factory.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameterArrayElement.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameterArrayElement.OfParameter.class).apply(); ObjectPropertyAssertion.of(MethodCall.ArgumentLoader.ForMethodParameterArrayElement.OfInvokedMethod.class).apply(); } public static class SimpleMethod { public String foo() { return null; } public String bar() { return BAR; } } public static class StaticExternalMethod { public static String bar() { return BAR; } } public static class InstanceMethod { public String foo() { return null; } public String bar() { return BAR; } } public abstract static class ArgumentCall { public abstract String foo(Target target); public static class Target { private final String value; public Target(String value) { this.value = value; } public String foo() { return value; } } } public abstract static class ArgumentCallDynamic { public abstract String foo(Object target); public static class Target { private final String value; public Target(String value) { this.value = value; } public String foo() { return value; } } } public static class SelfReference { public SelfReference foo() { return null; } } public static class SuperMethodInvocation { public String foo() { return FOO; } } public static class MethodCallWithExplicitArgument { public String foo(String value) { return value; } } public static class MethodCallWithTwoExplicitArguments { public String foo(String first, String second) { return first + second; } } public interface MethodCallDelegator { String invokeFoo(String... argument); } public interface IllegalMethodCallDelegator { String invokeFoo(String argument); } @SuppressWarnings("unused") public static class MethodCallWithField { public String foo; public String foo(String value) { return value; } } @SuppressWarnings("unused") public static class InvisibleMethodCallWithField extends InvisibleBase { private String foo; public String foo(String value) { return value; } } public static class InvisibleBase { public String foo; } public static class MethodCallWithThis { public MethodCallWithThis foo(MethodCallWithThis value) { return value; } } public static class MethodCallWithOwnType { public Class<?> foo(Class<?> value) { return value; } } public static class MethodCallAppending extends CallTraceable { public Object foo() { register(FOO); return null; } } public static class ExplicitTarget { public String foo() { return null; } } @SuppressWarnings("unused") public static class StaticIncompatibleExternalMethod { public static String bar(String value) { return null; } } public static class Foo { public static String bar(Object arg0, Object arg1) { return "" + arg0 + arg1; } } static class PackagePrivateType { public String foo() { return FOO; } public static String bar() { return BAR; } } public static class Bar { public void bar() { /* empty */ } } public static class SimpleStringMethod { public String foo() { return null; } } public static class Traceable extends CallTraceable implements Runnable, Callable<String> { @Override public String call() throws Exception { register(FOO); return FOO; } @Override public void run() { register(FOO); } } public static class NonVirtual { public static void foo() { /* empty */ } } public abstract static class ArrayConsuming { public abstract String foo(String arg1, String arg2); public String bar(String[] arg) { return arg[0] + arg[1]; } } }