提交 3b7691d5 编写于 作者: A Arjen Poutsma

SPR-6008 - @ResponseStatus on @ExceptionHandler method is ignored

上级 5680cd4a
...@@ -44,6 +44,7 @@ import org.springframework.util.ClassUtils; ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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; ...@@ -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 { ...@@ -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 { ...@@ -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; ...@@ -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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册