SPR-6008 - @ResponseStatus on @ExceptionHandler method is ignored
This commit is contained in:
parent
5680cd4a19
commit
3b7691d525
|
|
@ -44,6 +44,7 @@ import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.bind.support.WebArgumentResolver;
|
import org.springframework.web.bind.support.WebArgumentResolver;
|
||||||
import org.springframework.web.context.request.NativeWebRequest;
|
import org.springframework.web.context.request.NativeWebRequest;
|
||||||
import org.springframework.web.context.request.ServletWebRequest;
|
import org.springframework.web.context.request.ServletWebRequest;
|
||||||
|
|
@ -89,14 +90,14 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
if (handler != null) {
|
if (handler != null) {
|
||||||
Method handlerMethod = findBestExceptionHandlerMethod(handler, ex);
|
Method handlerMethod = findBestExceptionHandlerMethod(handler, ex);
|
||||||
if (handlerMethod != null) {
|
if (handlerMethod != null) {
|
||||||
NativeWebRequest webRequest = new ServletWebRequest(request, response);
|
ServletWebRequest webRequest = new ServletWebRequest(request, response);
|
||||||
try {
|
try {
|
||||||
Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, ex);
|
Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, ex);
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debug("Invoking request handler method: " + handlerMethod);
|
logger.debug("Invoking request handler method: " + handlerMethod);
|
||||||
}
|
}
|
||||||
Object retVal = doInvokeMethod(handlerMethod, handler, args);
|
Object retVal = doInvokeMethod(handlerMethod, handler, args);
|
||||||
return getModelAndView(retVal);
|
return getModelAndView(handlerMethod, handler.getClass(), retVal, webRequest);
|
||||||
}
|
}
|
||||||
catch (Exception invocationEx) {
|
catch (Exception invocationEx) {
|
||||||
logger.error("Invoking request method resulted in exception : " + handlerMethod, invocationEx);
|
logger.error("Invoking request method resulted in exception : " + handlerMethod, invocationEx);
|
||||||
|
|
@ -109,7 +110,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
/**
|
/**
|
||||||
* Finds the handler method that matches the thrown exception best.
|
* Finds the handler method that matches the thrown exception best.
|
||||||
*
|
*
|
||||||
* @param handler the handler object
|
* @param handler the handler object
|
||||||
* @param thrownException the exception to be handled
|
* @param thrownException the exception to be handled
|
||||||
* @return the best matching method; or <code>null</code> if none is found
|
* @return the best matching method; or <code>null</code> if none is found
|
||||||
*/
|
*/
|
||||||
|
|
@ -171,7 +172,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the best matching method. Uses the {@link DepthComparator}. */
|
/**
|
||||||
|
* Returns the best matching method. Uses the {@link DepthComparator}.
|
||||||
|
*/
|
||||||
private Method getBestMatchingMethod(Exception thrownException,
|
private Method getBestMatchingMethod(Exception thrownException,
|
||||||
Map<Class<? extends Throwable>, Method> resolverMethods) {
|
Map<Class<? extends Throwable>, Method> resolverMethods) {
|
||||||
if (!resolverMethods.isEmpty()) {
|
if (!resolverMethods.isEmpty()) {
|
||||||
|
|
@ -186,7 +189,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}. */
|
/**
|
||||||
|
* Resolves the arguments for the given method. Delegates to {@link #resolveCommonArgument}.
|
||||||
|
*/
|
||||||
private Object[] resolveHandlerArguments(Method handlerMethod,
|
private Object[] resolveHandlerArguments(Method handlerMethod,
|
||||||
Object handler,
|
Object handler,
|
||||||
NativeWebRequest webRequest,
|
NativeWebRequest webRequest,
|
||||||
|
|
@ -221,7 +226,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
* then checking {@link #resolveStandardArgument}.
|
* then checking {@link #resolveStandardArgument}.
|
||||||
*
|
*
|
||||||
* @param methodParameter the method parameter
|
* @param methodParameter the method parameter
|
||||||
* @param webRequest the request
|
* @param webRequest the request
|
||||||
* @param thrownException the exception thrown
|
* @param thrownException the exception thrown
|
||||||
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
|
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
|
||||||
*/
|
*/
|
||||||
|
|
@ -256,8 +261,8 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
* request {@link InputStream}, request {@link Reader}, response {@link OutputStream}, response {@link Writer},
|
* request {@link InputStream}, request {@link Reader}, response {@link OutputStream}, response {@link Writer},
|
||||||
* and the given {@code thrownException}.
|
* and the given {@code thrownException}.
|
||||||
*
|
*
|
||||||
* @param parameterType the method parameter type
|
* @param parameterType the method parameter type
|
||||||
* @param webRequest the request
|
* @param webRequest the request
|
||||||
* @param thrownException the exception thrown
|
* @param thrownException the exception thrown
|
||||||
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
|
* @return the argument value, or {@link WebArgumentResolver#UNRESOLVED}
|
||||||
*/
|
*/
|
||||||
|
|
@ -319,7 +324,16 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private ModelAndView getModelAndView(Object returnValue) {
|
private ModelAndView getModelAndView(Method handlerMethod,
|
||||||
|
Class handlerType,
|
||||||
|
Object returnValue,
|
||||||
|
ServletWebRequest webRequest) throws Exception {
|
||||||
|
|
||||||
|
if (handlerMethod.isAnnotationPresent(ResponseStatus.class)) {
|
||||||
|
ResponseStatus responseStatus = handlerMethod.getAnnotation(ResponseStatus.class);
|
||||||
|
HttpServletResponse response = webRequest.getResponse();
|
||||||
|
response.setStatus(responseStatus.value().value());
|
||||||
|
}
|
||||||
if (returnValue instanceof ModelAndView) {
|
if (returnValue instanceof ModelAndView) {
|
||||||
return (ModelAndView) returnValue;
|
return (ModelAndView) returnValue;
|
||||||
}
|
}
|
||||||
|
|
@ -343,7 +357,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Comparator capable of sorting exceptions based on their depth from the thrown exception type. */
|
/**
|
||||||
|
* Comparator capable of sorting exceptions based on their depth from the thrown exception type.
|
||||||
|
*/
|
||||||
private static class DepthComparator implements Comparator<Class<? extends Throwable>> {
|
private static class DepthComparator implements Comparator<Class<? extends Throwable>> {
|
||||||
|
|
||||||
private final Class<? extends Throwable> handlerExceptionType;
|
private final Class<? extends Throwable> handlerExceptionType;
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,9 @@ import org.springframework.mock.web.MockHttpServletResponse;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||||
import org.springframework.web.servlet.ModelAndView;
|
import org.springframework.web.servlet.ModelAndView;
|
||||||
|
import org.springframework.http.HttpStatus;
|
||||||
|
|
||||||
/** @author Arjen Poutsma */
|
/** @author Arjen Poutsma */
|
||||||
public class AnnotationMethodHandlerExceptionResolverTests {
|
public class AnnotationMethodHandlerExceptionResolverTests {
|
||||||
|
|
@ -56,6 +58,8 @@ public class AnnotationMethodHandlerExceptionResolverTests {
|
||||||
ModelAndView mav = exceptionResolver.resolveException(request, response, controller, ex);
|
ModelAndView mav = exceptionResolver.resolveException(request, response, controller, ex);
|
||||||
assertNotNull("No ModelAndView returned", mav);
|
assertNotNull("No ModelAndView returned", mav);
|
||||||
assertEquals("Invalid view name returned", "BindException", mav.getViewName());
|
assertEquals("Invalid view name returned", "BindException", mav.getViewName());
|
||||||
|
assertEquals("Invalid status code returned", 406, response.getStatus());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalStateException.class)
|
@Test(expected = IllegalStateException.class)
|
||||||
|
|
@ -74,6 +78,7 @@ public class AnnotationMethodHandlerExceptionResolverTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ExceptionHandler(BindException.class)
|
@ExceptionHandler(BindException.class)
|
||||||
|
@ResponseStatus(HttpStatus.NOT_ACCEPTABLE)
|
||||||
public String handleBindException(Exception ex, HttpServletResponse response) {
|
public String handleBindException(Exception ex, HttpServletResponse response) {
|
||||||
return ClassUtils.getShortName(ex.getClass());
|
return ClassUtils.getShortName(ex.getClass());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,10 @@ import java.lang.annotation.Target;
|
||||||
* only applicable in a Servlet environment).
|
* only applicable in a Servlet environment).
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
* <p>In Servlet environments, you can combine the {@code ExceptionHandler} annotation
|
||||||
|
* with {@link ResponseStatus @ResponseStatus}, to define the response status
|
||||||
|
* for the HTTP response.
|
||||||
|
*
|
||||||
* <p><b>NOTE: <code>@RequestMapping</code> will only be processed if a
|
* <p><b>NOTE: <code>@RequestMapping</code> will only be processed if a
|
||||||
* corresponding <code>HandlerMapping</code> (for type level annotations)
|
* corresponding <code>HandlerMapping</code> (for type level annotations)
|
||||||
* and/or <code>HandlerAdapter</code> (for method level annotations) is
|
* and/or <code>HandlerAdapter</code> (for method level annotations) is
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue