diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java index bbbaec44b3ce9d03d962fc2c18fa79c3b86927a3..e641fdc87a12580ab5bb4c13cb4cd8337563c47c 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolver.java @@ -44,6 +44,7 @@ import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.ReflectionUtils; 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.context.request.NativeWebRequest; import org.springframework.web.context.request.ServletWebRequest; @@ -89,14 +90,14 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc if (handler != null) { Method handlerMethod = findBestExceptionHandlerMethod(handler, ex); if (handlerMethod != null) { - NativeWebRequest webRequest = new ServletWebRequest(request, response); + ServletWebRequest webRequest = new ServletWebRequest(request, response); try { Object[] args = resolveHandlerArguments(handlerMethod, handler, webRequest, ex); if (logger.isDebugEnabled()) { logger.debug("Invoking request handler method: " + handlerMethod); } Object retVal = doInvokeMethod(handlerMethod, handler, args); - return getModelAndView(retVal); + return getModelAndView(handlerMethod, handler.getClass(), retVal, webRequest); } catch (Exception 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. * - * @param handler the handler object + * @param handler the handler object * @param thrownException the exception to be handled * @return the best matching method; or null if none is found */ @@ -171,7 +172,9 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc 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, Map, Method> resolverMethods) { 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, Object handler, NativeWebRequest webRequest, @@ -221,7 +226,7 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc * then checking {@link #resolveStandardArgument}. * * @param methodParameter the method parameter - * @param webRequest the request + * @param webRequest the request * @param thrownException the exception thrown * @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}, * and the given {@code thrownException}. * - * @param parameterType the method parameter type - * @param webRequest the request + * @param parameterType the method parameter type + * @param webRequest the request * @param thrownException the exception thrown * @return the argument value, or {@link WebArgumentResolver#UNRESOLVED} */ @@ -319,7 +324,16 @@ public class AnnotationMethodHandlerExceptionResolver extends AbstractHandlerExc } @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) { 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> { private final Class handlerExceptionType; diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolverTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolverTests.java index 9c8fcc3ee9f98e2f955bd87b3f50f239e2cd46b1..0924c03c87831cb072295727277afbeaccf4e9b6 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolverTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerExceptionResolverTests.java @@ -30,7 +30,9 @@ import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.util.ClassUtils; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.servlet.ModelAndView; +import org.springframework.http.HttpStatus; /** @author Arjen Poutsma */ public class AnnotationMethodHandlerExceptionResolverTests { @@ -56,6 +58,8 @@ public class AnnotationMethodHandlerExceptionResolverTests { ModelAndView mav = exceptionResolver.resolveException(request, response, controller, ex); assertNotNull("No ModelAndView returned", mav); assertEquals("Invalid view name returned", "BindException", mav.getViewName()); + assertEquals("Invalid status code returned", 406, response.getStatus()); + } @Test(expected = IllegalStateException.class) @@ -74,6 +78,7 @@ public class AnnotationMethodHandlerExceptionResolverTests { } @ExceptionHandler(BindException.class) + @ResponseStatus(HttpStatus.NOT_ACCEPTABLE) public String handleBindException(Exception ex, HttpServletResponse response) { return ClassUtils.getShortName(ex.getClass()); } diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java index 69586992c2a11dab1219748387ee2f0ec5e6aa95..8489902b479b83938613bfec43085f84405bd729 100644 --- a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java +++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/ExceptionHandler.java @@ -83,6 +83,10 @@ import java.lang.annotation.Target; * only applicable in a Servlet environment). * * + *

In Servlet environments, you can combine the {@code ExceptionHandler} annotation + * with {@link ResponseStatus @ResponseStatus}, to define the response status + * for the HTTP response. + * *

NOTE: @RequestMapping will only be processed if a * corresponding HandlerMapping (for type level annotations) * and/or HandlerAdapter (for method level annotations) is