Revised InvocableHandlerMethod exception messages (controller vs endpoint vs handler)
Introduces dedicated MethodArgumentResolutionException for spring-messaging invocations. Issue: SPR-15139
This commit is contained in:
parent
74596a6f1e
commit
047786acef
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -18,7 +18,7 @@ package org.springframework.messaging.handler.annotation.support;
|
||||||
|
|
||||||
import org.springframework.core.MethodParameter;
|
import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessagingException;
|
import org.springframework.messaging.handler.invocation.MethodArgumentResolutionException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base class for exceptions resulting from the invocation of
|
* Base class for exceptions resulting from the invocation of
|
||||||
|
@ -26,43 +26,24 @@ import org.springframework.messaging.MessagingException;
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0.3
|
* @since 4.0.3
|
||||||
|
* @deprecated as of 4.3.6, in favor of the invocation-associated
|
||||||
|
* {@link MethodArgumentResolutionException}
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public abstract class AbstractMethodArgumentResolutionException extends MessagingException {
|
public abstract class AbstractMethodArgumentResolutionException extends MethodArgumentResolutionException {
|
||||||
|
|
||||||
private final MethodParameter parameter;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a new instance providing the invalid {@code MethodParameter}.
|
|
||||||
*/
|
|
||||||
protected AbstractMethodArgumentResolutionException(Message<?> message, MethodParameter parameter) {
|
protected AbstractMethodArgumentResolutionException(Message<?> message, MethodParameter parameter) {
|
||||||
this(message, parameter, getMethodParamMessage(parameter));
|
super(message, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
protected AbstractMethodArgumentResolutionException(Message<?> message, MethodParameter parameter, String description) {
|
||||||
* Create a new instance providing the invalid {@code MethodParameter} and
|
super(message, parameter, description);
|
||||||
* a prepared description. Subclasses should prepend the description with
|
|
||||||
* the help of {@link #getMethodParamMessage(org.springframework.core.MethodParameter)}.
|
|
||||||
*/
|
|
||||||
protected AbstractMethodArgumentResolutionException(Message<?> message, MethodParameter param, String description) {
|
|
||||||
super(message, description);
|
|
||||||
this.parameter = param;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Return the MethodParameter that was rejected.
|
|
||||||
*/
|
|
||||||
public final MethodParameter getMethodParameter() {
|
|
||||||
return this.parameter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
protected static String getMethodParamMessage(MethodParameter param) {
|
protected static String getMethodParamMessage(MethodParameter param) {
|
||||||
return new StringBuilder("Could not resolve method parameter at index ")
|
return "";
|
||||||
.append(param.getParameterIndex()).append(" in method: ")
|
|
||||||
.append(param.getMethod().toGenericString()).append(" ").toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -29,27 +29,25 @@ import org.springframework.validation.ObjectError;
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
* @since 4.0.1
|
* @since 4.0.1
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings({"serial", "deprecation"})
|
||||||
public class MethodArgumentNotValidException extends AbstractMethodArgumentResolutionException {
|
public class MethodArgumentNotValidException extends AbstractMethodArgumentResolutionException {
|
||||||
|
|
||||||
private final BindingResult bindingResult;
|
private BindingResult bindingResult;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance with the invalid {@code MethodParameter}.
|
* Create a new instance with the invalid {@code MethodParameter}.
|
||||||
*/
|
*/
|
||||||
public MethodArgumentNotValidException(Message<?> message, MethodParameter parameter) {
|
public MethodArgumentNotValidException(Message<?> message, MethodParameter parameter) {
|
||||||
this(message, parameter, null);
|
super(message, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new instance with the invalid {@code MethodParameter} and a
|
* Create a new instance with the invalid {@code MethodParameter} and a
|
||||||
* {@link org.springframework.validation.BindingResult}.
|
* {@link org.springframework.validation.BindingResult}.
|
||||||
*/
|
*/
|
||||||
public MethodArgumentNotValidException(Message<?> message, MethodParameter parameter,
|
public MethodArgumentNotValidException(Message<?> message, MethodParameter parameter, BindingResult bindingResult) {
|
||||||
BindingResult bindingResult) {
|
super(message, parameter, getValidationErrorMessage(bindingResult));
|
||||||
|
|
||||||
super(message, parameter, getMethodParamMessage(parameter) + getValidationErrorMessage(bindingResult));
|
|
||||||
this.bindingResult = bindingResult;
|
this.bindingResult = bindingResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,17 +62,12 @@ public class MethodArgumentNotValidException extends AbstractMethodArgumentResol
|
||||||
|
|
||||||
|
|
||||||
private static String getValidationErrorMessage(BindingResult bindingResult) {
|
private static String getValidationErrorMessage(BindingResult bindingResult) {
|
||||||
if (bindingResult != null) {
|
StringBuilder sb = new StringBuilder();
|
||||||
StringBuilder sb = new StringBuilder();
|
sb.append(bindingResult.getErrorCount()).append(" error(s): ");
|
||||||
sb.append(", with ").append(bindingResult.getErrorCount()).append(" error(s): ");
|
for (ObjectError error : bindingResult.getAllErrors()) {
|
||||||
for (ObjectError error : bindingResult.getAllErrors()) {
|
sb.append("[").append(error).append("] ");
|
||||||
sb.append("[").append(error).append("] ");
|
|
||||||
}
|
|
||||||
return sb.toString();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return "";
|
|
||||||
}
|
}
|
||||||
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2015 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -20,20 +20,16 @@ import org.springframework.core.MethodParameter;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exception that indicates that a method argument has not the
|
* Exception that indicates that a method argument has not the expected type.
|
||||||
* expected type.
|
|
||||||
*
|
*
|
||||||
* @author Stephane Nicoll
|
* @author Stephane Nicoll
|
||||||
* @since 4.0.3
|
* @since 4.0.3
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings({"serial", "deprecation"})
|
||||||
public class MethodArgumentTypeMismatchException extends AbstractMethodArgumentResolutionException {
|
public class MethodArgumentTypeMismatchException extends AbstractMethodArgumentResolutionException {
|
||||||
|
|
||||||
/**
|
public MethodArgumentTypeMismatchException(Message<?> message, MethodParameter parameter, String description) {
|
||||||
* Create a new instance with the invalid {@code MethodParameter}.
|
super(message, parameter, description);
|
||||||
*/
|
|
||||||
public MethodArgumentTypeMismatchException(Message<?> message, MethodParameter param, String description) {
|
|
||||||
super(message, param, getMethodParamMessage(param) + description);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -139,36 +139,22 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
|
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args[i] == null) {
|
if (args[i] == null) {
|
||||||
String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
|
throw new MethodArgumentResolutionException(message, parameter,
|
||||||
throw new IllegalStateException(msg);
|
getArgumentResolutionErrorMessage("No suitable resolver for", i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getArgumentResolutionErrorMessage(String message, int index) {
|
private String getArgumentResolutionErrorMessage(String text, int index) {
|
||||||
MethodParameter param = getMethodParameters()[index];
|
Class<?> paramType = getMethodParameters()[index].getParameterType();
|
||||||
message += " [" + index + "] [type=" + param.getParameterType().getName() + "]";
|
return text + " argument " + index + " of type '" + paramType.getName() + "'";
|
||||||
return getDetailedErrorMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds HandlerMethod details such as the controller type and method
|
|
||||||
* signature to the given error message.
|
|
||||||
* @param message error message to append the HandlerMethod details to
|
|
||||||
*/
|
|
||||||
protected String getDetailedErrorMessage(String message) {
|
|
||||||
StringBuilder sb = new StringBuilder(message).append("\n");
|
|
||||||
sb.append("HandlerMethod details: \n");
|
|
||||||
sb.append("Controller [").append(getBeanType().getName()).append("]\n");
|
|
||||||
sb.append("Method [").append(getBridgedMethod().toGenericString()).append("]\n");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -197,8 +183,8 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
assertTargetBean(getBridgedMethod(), getBean(), args);
|
assertTargetBean(getBridgedMethod(), getBean(), args);
|
||||||
String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
|
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
|
||||||
throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
|
throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
// Unwrap for HandlerExceptionResolvers ...
|
// Unwrap for HandlerExceptionResolvers ...
|
||||||
|
@ -213,33 +199,33 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
throw (Exception) targetException;
|
throw (Exception) targetException;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
|
String text = getInvocationErrorMessage("Failed to invoke handler method", args);
|
||||||
throw new IllegalStateException(msg, targetException);
|
throw new IllegalStateException(text, targetException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert that the target bean class is an instance of the class where the given
|
* Assert that the target bean class is an instance of the class where the given
|
||||||
* method is declared. In some cases the actual controller instance at request-
|
* method is declared. In some cases the actual endpoint instance at request-
|
||||||
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
|
* processing time may be a JDK dynamic proxy (lazy initialization, prototype
|
||||||
* beans, and others). {@code @Controller}'s that require proxying should prefer
|
* beans, and others). Endpoint classes that require proxying should prefer
|
||||||
* class-based proxy mechanisms.
|
* class-based proxy mechanisms.
|
||||||
*/
|
*/
|
||||||
private void assertTargetBean(Method method, Object targetBean, Object[] args) {
|
private void assertTargetBean(Method method, Object targetBean, Object[] args) {
|
||||||
Class<?> methodDeclaringClass = method.getDeclaringClass();
|
Class<?> methodDeclaringClass = method.getDeclaringClass();
|
||||||
Class<?> targetBeanClass = targetBean.getClass();
|
Class<?> targetBeanClass = targetBean.getClass();
|
||||||
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
|
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
|
||||||
String msg = "The mapped controller method class '" + methodDeclaringClass.getName() +
|
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
|
||||||
"' is not an instance of the actual controller bean class '" +
|
"' is not an instance of the actual endpoint bean class '" +
|
||||||
targetBeanClass.getName() + "'. If the controller requires proxying " +
|
targetBeanClass.getName() + "'. If the endpoint requires proxying " +
|
||||||
"(e.g. due to @Transactional), please use class-based proxying.";
|
"(e.g. due to @Transactional), please use class-based proxying.";
|
||||||
throw new IllegalStateException(getInvocationErrorMessage(msg, args));
|
throw new IllegalStateException(getInvocationErrorMessage(text, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getInvocationErrorMessage(String message, Object[] resolvedArgs) {
|
private String getInvocationErrorMessage(String text, Object[] resolvedArgs) {
|
||||||
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(message));
|
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(text));
|
||||||
sb.append("Resolved arguments: \n");
|
sb.append("Resolved arguments: \n");
|
||||||
for (int i = 0; i < resolvedArgs.length; i++) {
|
for (int i = 0; i < resolvedArgs.length; i++) {
|
||||||
sb.append("[").append(i).append("] ");
|
sb.append("[").append(i).append("] ");
|
||||||
|
@ -254,6 +240,19 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds HandlerMethod details such as the bean type and method signature to the message.
|
||||||
|
* @param text error message to append the HandlerMethod details to
|
||||||
|
*/
|
||||||
|
protected String getDetailedErrorMessage(String text) {
|
||||||
|
StringBuilder sb = new StringBuilder(text).append("\n");
|
||||||
|
sb.append("HandlerMethod details: \n");
|
||||||
|
sb.append("Endpoint [").append(getBeanType().getName()).append("]\n");
|
||||||
|
sb.append("Method [").append(getBridgedMethod().toGenericString()).append("]\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
MethodParameter getAsyncReturnValueType(Object returnValue) {
|
MethodParameter getAsyncReturnValueType(Object returnValue) {
|
||||||
return new AsyncResultMethodParameter(returnValue);
|
return new AsyncResultMethodParameter(returnValue);
|
||||||
}
|
}
|
||||||
|
@ -268,7 +267,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
public AsyncResultMethodParameter(Object returnValue) {
|
public AsyncResultMethodParameter(Object returnValue) {
|
||||||
super(-1);
|
super(-1);
|
||||||
this.returnValue = returnValue;
|
this.returnValue = returnValue;
|
||||||
this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric(0);
|
this.returnType = ResolvableType.forType(super.getGenericParameterType()).getGeneric();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected AsyncResultMethodParameter(AsyncResultMethodParameter original) {
|
protected AsyncResultMethodParameter(AsyncResultMethodParameter original) {
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2002-2017 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.messaging.handler.invocation;
|
||||||
|
|
||||||
|
import org.springframework.core.MethodParameter;
|
||||||
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.MessagingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Common exception resulting from the invocation of
|
||||||
|
* {@link org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver}.
|
||||||
|
*
|
||||||
|
* @author Juergen Hoeller
|
||||||
|
* @since 4.3.6
|
||||||
|
* @see HandlerMethodArgumentResolver
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("serial")
|
||||||
|
public class MethodArgumentResolutionException extends MessagingException {
|
||||||
|
|
||||||
|
private final MethodParameter parameter;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance providing the invalid {@code MethodParameter}.
|
||||||
|
*/
|
||||||
|
public MethodArgumentResolutionException(Message<?> message, MethodParameter parameter) {
|
||||||
|
super(message, getMethodParameterMessage(parameter));
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new instance providing the invalid {@code MethodParameter} and
|
||||||
|
* a prepared description.
|
||||||
|
*/
|
||||||
|
public MethodArgumentResolutionException(Message<?> message, MethodParameter parameter, String description) {
|
||||||
|
super(message, getMethodParameterMessage(parameter) + ": " + description);
|
||||||
|
this.parameter = parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the MethodParameter that was rejected.
|
||||||
|
*/
|
||||||
|
public final MethodParameter getMethodParameter() {
|
||||||
|
return this.parameter;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static String getMethodParameterMessage(MethodParameter parameter) {
|
||||||
|
return "Could not resolve method parameter at index " + parameter.getParameterIndex() +
|
||||||
|
" in " + parameter.getMethod().toGenericString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -41,6 +41,7 @@ import org.springframework.messaging.converter.MessageConverter;
|
||||||
import org.springframework.messaging.handler.annotation.Payload;
|
import org.springframework.messaging.handler.annotation.Payload;
|
||||||
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
import org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolver;
|
||||||
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
|
import org.springframework.messaging.handler.invocation.InvocableHandlerMethod;
|
||||||
|
import org.springframework.messaging.handler.invocation.MethodArgumentResolutionException;
|
||||||
import org.springframework.messaging.support.MessageBuilder;
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.validation.Errors;
|
import org.springframework.validation.Errors;
|
||||||
|
@ -53,13 +54,14 @@ import static org.junit.Assert.*;
|
||||||
*/
|
*/
|
||||||
public class DefaultMessageHandlerMethodFactoryTests {
|
public class DefaultMessageHandlerMethodFactoryTests {
|
||||||
|
|
||||||
|
private final SampleBean sample = new SampleBean();
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final TestName name = new TestName();
|
public final TestName name = new TestName();
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final ExpectedException thrown = ExpectedException.none();
|
public final ExpectedException thrown = ExpectedException.none();
|
||||||
|
|
||||||
private final SampleBean sample = new SampleBean();
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void customConversion() throws Exception {
|
public void customConversion() throws Exception {
|
||||||
|
@ -146,7 +148,7 @@ public class DefaultMessageHandlerMethodFactoryTests {
|
||||||
InvocableHandlerMethod invocableHandlerMethod2 =
|
InvocableHandlerMethod invocableHandlerMethod2 =
|
||||||
createInvocableHandlerMethod(instance, "simpleString", String.class);
|
createInvocableHandlerMethod(instance, "simpleString", String.class);
|
||||||
|
|
||||||
thrown.expect(IllegalStateException.class);
|
thrown.expect(MethodArgumentResolutionException.class);
|
||||||
thrown.expectMessage("No suitable resolver for");
|
thrown.expectMessage("No suitable resolver for");
|
||||||
invocableHandlerMethod2.invoke(message);
|
invocableHandlerMethod2.invoke(message);
|
||||||
}
|
}
|
||||||
|
@ -240,4 +242,5 @@ public class DefaultMessageHandlerMethodFactoryTests {
|
||||||
return Locale.getDefault();
|
return Locale.getDefault();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -45,6 +45,7 @@ import org.springframework.web.server.ServerWebExchange;
|
||||||
* a {@link ServerWebExchange} and use that to invoke the underlying method.
|
* a {@link ServerWebExchange} and use that to invoke the underlying method.
|
||||||
*
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Juergen Hoeller
|
||||||
* @since 5.0
|
* @since 5.0
|
||||||
*/
|
*/
|
||||||
public class InvocableHandlerMethod extends HandlerMethod {
|
public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
|
@ -89,14 +90,13 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke the method for the given exchange.
|
* Invoke the method for the given exchange.
|
||||||
*
|
|
||||||
* @param exchange the current exchange
|
* @param exchange the current exchange
|
||||||
* @param bindingContext the binding context to use
|
* @param bindingContext the binding context to use
|
||||||
* @param providedArgs optional list of argument values to match by type
|
* @param providedArgs optional list of argument values to match by type
|
||||||
* @return Mono with a {@link HandlerResult}.
|
* @return Mono with a {@link HandlerResult}.
|
||||||
*/
|
*/
|
||||||
public Mono<HandlerResult> invoke(ServerWebExchange exchange,
|
public Mono<HandlerResult> invoke(ServerWebExchange exchange, BindingContext bindingContext,
|
||||||
BindingContext bindingContext, Object... providedArgs) {
|
Object... providedArgs) {
|
||||||
|
|
||||||
return resolveArguments(exchange, bindingContext, providedArgs).then(args -> {
|
return resolveArguments(exchange, bindingContext, providedArgs).then(args -> {
|
||||||
try {
|
try {
|
||||||
|
@ -108,14 +108,13 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
return Mono.error(ex.getTargetException());
|
return Mono.error(ex.getTargetException());
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
String msg = getInvocationErrorMessage(args);
|
return Mono.error(new IllegalStateException(getInvocationErrorMessage(args)));
|
||||||
return Mono.error(new IllegalStateException(msg));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Object[]> resolveArguments(ServerWebExchange exchange,
|
private Mono<Object[]> resolveArguments(ServerWebExchange exchange, BindingContext bindingContext,
|
||||||
BindingContext bindingContext, Object... providedArgs) {
|
Object... providedArgs) {
|
||||||
|
|
||||||
if (ObjectUtils.isEmpty(getMethodParameters())) {
|
if (ObjectUtils.isEmpty(getMethodParameters())) {
|
||||||
return EMPTY_ARGS;
|
return EMPTY_ARGS;
|
||||||
|
@ -125,7 +124,7 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
.map(param -> {
|
.map(param -> {
|
||||||
param.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
param.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||||
GenericTypeResolver.resolveParameterType(param, getBean().getClass());
|
GenericTypeResolver.resolveParameterType(param, getBean().getClass());
|
||||||
return findProvidedArg(param, providedArgs)
|
return findProvidedArgument(param, providedArgs)
|
||||||
.map(Mono::just)
|
.map(Mono::just)
|
||||||
.orElseGet(() -> {
|
.orElseGet(() -> {
|
||||||
HandlerMethodArgumentResolver resolver = findResolver(param);
|
HandlerMethodArgumentResolver resolver = findResolver(param);
|
||||||
|
@ -144,12 +143,12 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Optional<Object> findProvidedArg(MethodParameter param, Object... providedArgs) {
|
private Optional<Object> findProvidedArgument(MethodParameter parameter, Object... providedArgs) {
|
||||||
if (ObjectUtils.isEmpty(providedArgs)) {
|
if (ObjectUtils.isEmpty(providedArgs)) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
return Arrays.stream(providedArgs)
|
return Arrays.stream(providedArgs)
|
||||||
.filter(arg -> param.getParameterType().isInstance(arg))
|
.filter(arg -> parameter.getParameterType().isInstance(arg))
|
||||||
.findFirst();
|
.findFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,34 +156,33 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
return this.resolvers.stream()
|
return this.resolvers.stream()
|
||||||
.filter(r -> r.supportsParameter(param))
|
.filter(r -> r.supportsParameter(param))
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElseThrow(() -> getArgumentError("No resolver for ", param, null));
|
.orElseThrow(() -> getArgumentError("No suitable resolver for", param, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<Object> resolveArg(HandlerMethodArgumentResolver resolver, MethodParameter param,
|
private Mono<Object> resolveArg(HandlerMethodArgumentResolver resolver, MethodParameter parameter,
|
||||||
BindingContext bindingContext, ServerWebExchange exchange) {
|
BindingContext bindingContext, ServerWebExchange exchange) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return resolver.resolveArgument(param, bindingContext, exchange)
|
return resolver.resolveArgument(parameter, bindingContext, exchange)
|
||||||
.defaultIfEmpty(NO_ARG_VALUE)
|
.defaultIfEmpty(NO_ARG_VALUE)
|
||||||
.doOnError(cause -> {
|
.doOnError(cause -> {
|
||||||
if(logger.isDebugEnabled()) {
|
if(logger.isDebugEnabled()) {
|
||||||
logger.debug(getDetailedErrorMessage("Error resolving ", param), cause);
|
logger.debug(getDetailedErrorMessage("Failed to resolve", parameter), cause);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
throw getArgumentError("Error resolving ", param, ex);
|
throw getArgumentError("Failed to resolve", parameter, ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private IllegalStateException getArgumentError(String message, MethodParameter param, Throwable ex) {
|
private IllegalStateException getArgumentError(String text, MethodParameter parameter, Throwable ex) {
|
||||||
return new IllegalStateException(getDetailedErrorMessage(message, param), ex);
|
return new IllegalStateException(getDetailedErrorMessage(text, parameter), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDetailedErrorMessage(String message, MethodParameter param) {
|
private String getDetailedErrorMessage(String text, MethodParameter param) {
|
||||||
return message + "argument [" + param.getParameterIndex() + "] " +
|
return text + " argument " + param.getParameterIndex() + " of type '" +
|
||||||
"of type [" + param.getParameterType().getName() + "] " +
|
param.getParameterType().getName() + "' on " + getBridgedMethod().toGenericString();
|
||||||
"on method [" + getBridgedMethod().toGenericString() + "]";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object doInvoke(Object[] args) throws Exception {
|
private Object doInvoke(Object[] args) throws Exception {
|
||||||
|
@ -207,8 +205,8 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
"[" + i + "][type=" + args[i].getClass().getName() + "][value=" + args[i] + "]" :
|
"[" + i + "][type=" + args[i].getClass().getName() + "][value=" + args[i] + "]" :
|
||||||
"[" + i + "][null]"))
|
"[" + i + "][null]"))
|
||||||
.collect(Collectors.joining(",", " ", " "));
|
.collect(Collectors.joining(",", " ", " "));
|
||||||
return "Failed to invoke controller with resolved arguments:" + argumentDetails +
|
return "Failed to invoke handler method with resolved arguments:" + argumentDetails +
|
||||||
"on method [" + getBridgedMethod().toGenericString() + "]";
|
"on " + getBridgedMethod().toGenericString();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -34,18 +34,16 @@ import org.springframework.web.server.UnsupportedMediaTypeStatusException;
|
||||||
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
import org.springframework.web.server.adapter.DefaultServerWebExchange;
|
||||||
import org.springframework.web.server.session.MockWebSessionManager;
|
import org.springframework.web.server.session.MockWebSessionManager;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.instanceOf;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.mockito.Mockito.any;
|
import static org.mockito.Mockito.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.*;
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unit tests for {@link InvocableHandlerMethod}.
|
* Unit tests for {@link InvocableHandlerMethod}.
|
||||||
|
*
|
||||||
* @author Rossen Stoyanchev
|
* @author Rossen Stoyanchev
|
||||||
|
* @author Juergen Hoeller
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
|
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
|
||||||
public class InvocableHandlerMethodTests {
|
public class InvocableHandlerMethodTests {
|
||||||
|
@ -93,14 +91,14 @@ public class InvocableHandlerMethodTests {
|
||||||
InvocableHandlerMethod hm = handlerMethod("singleArg");
|
InvocableHandlerMethod hm = handlerMethod("singleArg");
|
||||||
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
||||||
|
|
||||||
StepVerifier.create(mono)
|
try {
|
||||||
.expectNextCount(0)
|
mono.block();
|
||||||
.consumeErrorWith(error -> {
|
fail("Expected IllegalStateException");
|
||||||
assertThat(error, instanceOf(IllegalStateException.class));
|
}
|
||||||
assertThat(error.getMessage(), is("No resolver for argument [0] of type [java.lang.String] " +
|
catch (IllegalStateException ex) {
|
||||||
"on method [" + hm.getMethod().toGenericString() + "]"));
|
assertThat(ex.getMessage(), is("No suitable resolver for argument 0 of type 'java.lang.String' " +
|
||||||
})
|
"on " + hm.getMethod().toGenericString()));
|
||||||
.verify();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -109,13 +107,13 @@ public class InvocableHandlerMethodTests {
|
||||||
addResolver(hm, Mono.error(new UnsupportedMediaTypeStatusException("boo")));
|
addResolver(hm, Mono.error(new UnsupportedMediaTypeStatusException("boo")));
|
||||||
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
||||||
|
|
||||||
StepVerifier.create(mono)
|
try {
|
||||||
.expectNextCount(0)
|
mono.block();
|
||||||
.consumeErrorWith(error -> {
|
fail("Expected UnsupportedMediaTypeStatusException");
|
||||||
assertThat(error, instanceOf(UnsupportedMediaTypeStatusException.class));
|
}
|
||||||
assertThat(error.getMessage(), is("Request failure [status: 415, reason: \"boo\"]"));
|
catch (UnsupportedMediaTypeStatusException ex) {
|
||||||
})
|
assertThat(ex.getMessage(), is("Request failure [status: 415, reason: \"boo\"]"));
|
||||||
.verify();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -124,15 +122,15 @@ public class InvocableHandlerMethodTests {
|
||||||
addResolver(hm, Mono.just(1));
|
addResolver(hm, Mono.just(1));
|
||||||
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
||||||
|
|
||||||
StepVerifier.create(mono)
|
try {
|
||||||
.expectNextCount(0)
|
mono.block();
|
||||||
.consumeErrorWith(error -> {
|
fail("Expected IllegalStateException");
|
||||||
assertThat(error, instanceOf(IllegalStateException.class));
|
}
|
||||||
assertThat(error.getMessage(), is("Failed to invoke controller with resolved arguments: " +
|
catch (IllegalStateException ex) {
|
||||||
"[0][type=java.lang.Integer][value=1] " +
|
assertThat(ex.getMessage(), is("Failed to invoke handler method with resolved arguments: " +
|
||||||
"on method [" + hm.getMethod().toGenericString() + "]"));
|
"[0][type=java.lang.Integer][value=1] " +
|
||||||
})
|
"on " + hm.getMethod().toGenericString()));
|
||||||
.verify();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -140,13 +138,13 @@ public class InvocableHandlerMethodTests {
|
||||||
InvocableHandlerMethod hm = handlerMethod("exceptionMethod");
|
InvocableHandlerMethod hm = handlerMethod("exceptionMethod");
|
||||||
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
Mono<HandlerResult> mono = hm.invoke(this.exchange, new BindingContext());
|
||||||
|
|
||||||
StepVerifier.create(mono)
|
try {
|
||||||
.expectNextCount(0)
|
mono.block();
|
||||||
.consumeErrorWith(error -> {
|
fail("Expected IllegalStateException");
|
||||||
assertThat(error, instanceOf(IllegalStateException.class));
|
}
|
||||||
assertThat(error.getMessage(), is("boo"));
|
catch (IllegalStateException ex) {
|
||||||
})
|
assertThat(ex.getMessage(), is("boo"));
|
||||||
.verify();
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -163,36 +163,23 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
}
|
}
|
||||||
catch (Exception ex) {
|
catch (Exception ex) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug(getArgumentResolutionErrorMessage("Error resolving argument", i), ex);
|
logger.debug(getArgumentResolutionErrorMessage("Failed to resolve", i), ex);
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (args[i] == null) {
|
if (args[i] == null) {
|
||||||
String msg = getArgumentResolutionErrorMessage("No suitable resolver for argument", i);
|
throw new IllegalStateException("Could not resolve method parameter at index " +
|
||||||
throw new IllegalStateException(msg);
|
parameter.getParameterIndex() + " in " + parameter.getMethod().toGenericString() +
|
||||||
|
": " + getArgumentResolutionErrorMessage("No suitable resolver for", i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getArgumentResolutionErrorMessage(String message, int index) {
|
private String getArgumentResolutionErrorMessage(String text, int index) {
|
||||||
MethodParameter param = getMethodParameters()[index];
|
Class<?> paramType = getMethodParameters()[index].getParameterType();
|
||||||
message += " [" + index + "] [type=" + param.getParameterType().getName() + "]";
|
return text + " argument " + index + " of type '" + paramType.getName() + "'";
|
||||||
return getDetailedErrorMessage(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds HandlerMethod details such as the controller type and method
|
|
||||||
* signature to the given error message.
|
|
||||||
* @param message error message to append the HandlerMethod details to
|
|
||||||
*/
|
|
||||||
protected String getDetailedErrorMessage(String message) {
|
|
||||||
StringBuilder sb = new StringBuilder(message).append("\n");
|
|
||||||
sb.append("HandlerMethod details: \n");
|
|
||||||
sb.append("Controller [").append(getBeanType().getName()).append("]\n");
|
|
||||||
sb.append("Method [").append(getBridgedMethod().toGenericString()).append("]\n");
|
|
||||||
return sb.toString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -221,8 +208,8 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
assertTargetBean(getBridgedMethod(), getBean(), args);
|
assertTargetBean(getBridgedMethod(), getBean(), args);
|
||||||
String message = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
|
String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument");
|
||||||
throw new IllegalStateException(getInvocationErrorMessage(message, args), ex);
|
throw new IllegalStateException(getInvocationErrorMessage(text, args), ex);
|
||||||
}
|
}
|
||||||
catch (InvocationTargetException ex) {
|
catch (InvocationTargetException ex) {
|
||||||
// Unwrap for HandlerExceptionResolvers ...
|
// Unwrap for HandlerExceptionResolvers ...
|
||||||
|
@ -237,8 +224,8 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
throw (Exception) targetException;
|
throw (Exception) targetException;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
String msg = getInvocationErrorMessage("Failed to invoke controller method", args);
|
String text = getInvocationErrorMessage("Failed to invoke handler method", args);
|
||||||
throw new IllegalStateException(msg, targetException);
|
throw new IllegalStateException(text, targetException);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -254,16 +241,16 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
Class<?> methodDeclaringClass = method.getDeclaringClass();
|
Class<?> methodDeclaringClass = method.getDeclaringClass();
|
||||||
Class<?> targetBeanClass = targetBean.getClass();
|
Class<?> targetBeanClass = targetBean.getClass();
|
||||||
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
|
if (!methodDeclaringClass.isAssignableFrom(targetBeanClass)) {
|
||||||
String msg = "The mapped controller method class '" + methodDeclaringClass.getName() +
|
String text = "The mapped handler method class '" + methodDeclaringClass.getName() +
|
||||||
"' is not an instance of the actual controller bean class '" +
|
"' is not an instance of the actual controller bean class '" +
|
||||||
targetBeanClass.getName() + "'. If the controller requires proxying " +
|
targetBeanClass.getName() + "'. If the controller requires proxying " +
|
||||||
"(e.g. due to @Transactional), please use class-based proxying.";
|
"(e.g. due to @Transactional), please use class-based proxying.";
|
||||||
throw new IllegalStateException(getInvocationErrorMessage(msg, args));
|
throw new IllegalStateException(getInvocationErrorMessage(text, args));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getInvocationErrorMessage(String message, Object[] resolvedArgs) {
|
private String getInvocationErrorMessage(String text, Object[] resolvedArgs) {
|
||||||
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(message));
|
StringBuilder sb = new StringBuilder(getDetailedErrorMessage(text));
|
||||||
sb.append("Resolved arguments: \n");
|
sb.append("Resolved arguments: \n");
|
||||||
for (int i = 0; i < resolvedArgs.length; i++) {
|
for (int i = 0; i < resolvedArgs.length; i++) {
|
||||||
sb.append("[").append(i).append("] ");
|
sb.append("[").append(i).append("] ");
|
||||||
|
@ -278,4 +265,16 @@ public class InvocableHandlerMethod extends HandlerMethod {
|
||||||
return sb.toString();
|
return sb.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds HandlerMethod details such as the bean type and method signature to the message.
|
||||||
|
* @param text error message to append the HandlerMethod details to
|
||||||
|
*/
|
||||||
|
protected String getDetailedErrorMessage(String text) {
|
||||||
|
StringBuilder sb = new StringBuilder(text).append("\n");
|
||||||
|
sb.append("HandlerMethod details: \n");
|
||||||
|
sb.append("Controller [").append(getBeanType().getName()).append("]\n");
|
||||||
|
sb.append("Method [").append(getBridgedMethod().toGenericString()).append("]\n");
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright 2002-2016 the original author or authors.
|
* Copyright 2002-2017 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
@ -93,7 +93,7 @@ public class InvocableHandlerMethodTests {
|
||||||
fail("Expected exception");
|
fail("Expected exception");
|
||||||
}
|
}
|
||||||
catch (IllegalStateException ex) {
|
catch (IllegalStateException ex) {
|
||||||
assertTrue(ex.getMessage().contains("No suitable resolver for argument [0] [type=java.lang.Integer]"));
|
assertTrue(ex.getMessage().contains("No suitable resolver for argument 0 of type 'java.lang.Integer'"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,7 +192,7 @@ public class InvocableHandlerMethodTests {
|
||||||
catch (IllegalStateException actual) {
|
catch (IllegalStateException actual) {
|
||||||
assertNotNull(actual.getCause());
|
assertNotNull(actual.getCause());
|
||||||
assertSame(expected, actual.getCause());
|
assertSame(expected, actual.getCause());
|
||||||
assertTrue(actual.getMessage().contains("Failed to invoke controller method"));
|
assertTrue(actual.getMessage().contains("Failed to invoke handler method"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue