/** * Build a {@code ResolvableMethod} from the provided filters which must * resolve to a unique, single method. * <p>See additional resolveXxx shortcut methods going directly to * {@link Method} or return type parameter. * @throws IllegalStateException for no match or multiple matches */ public ResolvableMethod build() { Set<Method> methods = MethodIntrospector.selectMethods(this.objectClass, this::isMatch); Assert.state(!methods.isEmpty(), () -> "No matching method: " + this); Assert.state(methods.size() == 1, () -> "Multiple matching methods: " + this + formatMethods(methods)); return new ResolvableMethod(methods.iterator().next()); }
@Override public String toString() { return "ResolvableMethod=" + formatMethod(); }
private String formatMethod() { return (method().getName() + Arrays.stream(this.method.getParameters()) .map(this::formatParameter) .collect(joining(",\n\t", "(\n\t", "\n)"))); }
@Test // Based on SPR-13917 (spring-web) public void invocationErrorMessage() throws Exception { this.resolvers.addResolver(new StubArgumentResolver(double.class)); try { Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0.0)).method(); invoke(new Handler(), method); fail(); } catch (IllegalStateException ex) { assertThat(ex.getMessage(), containsString("Illegal argument")); } }
/** * Resolve and return the declared return type equivalent to: * <p>{@code build().returnType()} */ public final MethodParameter resolveReturnType() { return build().returnType(); }
@Test public void invocationTargetException() throws Exception { Handler handler = new Handler(); Method method = ResolvableMethod.on(Handler.class).argTypes(Throwable.class).resolveMethod(); Throwable expected = null; try {
@Test public void resolveProvidedArg() throws Exception { Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); Object value = invoke(new Handler(), method, 99, "value"); assertNotNull(value); assertEquals(String.class, value.getClass()); assertEquals("99-value", value); }
/** * Shortcut to the unique return type equivalent to: * <p>{@code returning(returnType).build().returnType()} * @param returnType the return type * @param generics optional array of generic types */ public MethodParameter resolveReturnType(Class<?> returnType, Class<?>... generics) { return returning(returnType, generics).build().returnType(); }
@Test public void exceptionInResolvingArg() throws Exception { this.resolvers.addResolver(new ExceptionRaisingArgumentResolver()); try { Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); invoke(new Handler(), method); fail("Expected exception"); } catch (IllegalArgumentException ex) { // expected - allow HandlerMethodArgumentResolver exceptions to propagate } }
/** * Shortcut to the unique return type equivalent to: * <p>{@code returning(returnType).build().returnType()} * @param returnType the return type * @param generic at least one generic type * @param generics optional extra generic types */ public MethodParameter resolveReturnType(Class<?> returnType, ResolvableType generic, ResolvableType... generics) { return returning(returnType, generic, generics).build().returnType(); }
/** * Resolve and return the {@code Method} equivalent to: * <p>{@code build().method()} */ public final Method resolveMethod() { return build().method(); }
public ResolvableMethod mockCall(Consumer<T> invoker) { MethodInvocationInterceptor interceptor = new MethodInvocationInterceptor(); T proxy = initProxy(this.objectClass, interceptor); invoker.accept(proxy); Method method = interceptor.getInvokedMethod(); return new ResolvableMethod(method); }
@Test public void cannotResolveArg() throws Exception { try { Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); invoke(new Handler(), method); fail("Expected exception"); } catch (MethodArgumentResolutionException ex) { assertNotNull(ex.getMessage()); assertTrue(ex.getMessage().contains("Could not resolve parameter [0]")); } }
public MethodParameter resolveReturnType(ResolvableType returnType) { return returning(returnType).build().returnType(); }
/** * Resolve and return the {@code Method} equivalent to: * <p>{@code named(methodName).build().method()} */ public Method resolveMethod(String methodName) { return named(methodName).build().method(); }
@Test public void illegalArgumentException() throws Exception { this.resolvers.addResolver(new StubArgumentResolver(Integer.class, "__not_an_int__")); this.resolvers.addResolver(new StubArgumentResolver("value")); try { Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); invoke(new Handler(), method); fail("Expected exception"); } catch (IllegalStateException ex) { assertNotNull("Exception not wrapped", ex.getCause()); assertTrue(ex.getCause() instanceof IllegalArgumentException); assertTrue(ex.getMessage().contains("Endpoint [")); assertTrue(ex.getMessage().contains("Method [")); assertTrue(ex.getMessage().contains("with argument values:")); assertTrue(ex.getMessage().contains("[0] [type=java.lang.String] [value=__not_an_int__]")); assertTrue(ex.getMessage().contains("[1] [type=java.lang.String] [value=value")); } }
@Test public void resolveProvidedArgFirst() throws Exception { this.resolvers.addResolver(new StubArgumentResolver(1)); this.resolvers.addResolver(new StubArgumentResolver("value1")); Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); Object value = invoke(new Handler(), method, 2, "value2"); assertEquals("2-value2", value); }
@Test public void resolveNoArgValue() throws Exception { this.resolvers.addResolver(new StubArgumentResolver(Integer.class)); this.resolvers.addResolver(new StubArgumentResolver(String.class)); Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); Object value = invoke(new Handler(), method); assertEquals(1, getStubResolver(0).getResolvedParameters().size()); assertEquals(1, getStubResolver(1).getResolvedParameters().size()); assertEquals("null-null", value); }
@Test public void resolveArg() throws Exception { this.resolvers.addResolver(new StubArgumentResolver(99)); this.resolvers.addResolver(new StubArgumentResolver("value")); Method method = ResolvableMethod.on(Handler.class).mockCall(c -> c.handle(0, "")).method(); Object value = invoke(new Handler(), method); assertEquals(1, getStubResolver(0).getResolvedParameters().size()); assertEquals(1, getStubResolver(1).getResolvedParameters().size()); assertEquals("99-value", value); assertEquals("intArg", getStubResolver(0).getResolvedParameters().get(0).getParameterName()); assertEquals("stringArg", getStubResolver(1).getResolvedParameters().get(0).getParameterName()); }