From efe3996cf9247180549694ee38a9b3e36518d23a Mon Sep 17 00:00:00 2001 From: Rossen Stoyanchev Date: Mon, 24 Oct 2016 15:59:54 +0100 Subject: [PATCH] Respect ModelAndView.status in @ExceptionHandler Issue: SPR-14006 --- .../web/servlet/ModelAndView.java | 4 ++- .../ExceptionHandlerExceptionResolver.java | 6 ++++- ...nnotationControllerHandlerMethodTests.java | 26 +++++++++++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java index 66fd742922..5323c1a8f4 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/ModelAndView.java @@ -127,7 +127,8 @@ public class ModelAndView { * @param model Map of model names (Strings) to model objects * (Objects). Model entries may not be {@code null}, but the * model Map may be {@code null} if there is no model data. - * @param status an alternative status code to use for the response. + * @param status an alternative status code to use for the response; + * The response status is set just prior to View rendering. * @since 4.3 */ public ModelAndView(String viewName, Map model, HttpStatus status) { @@ -240,6 +241,7 @@ public class ModelAndView { /** * Set the HTTP status to use for the response. + *

The response status is set just prior to View rendering. * @since 4.3 */ public void setStatus(HttpStatus status) { diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java index 4f138e62d5..5a26739b9d 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java @@ -32,11 +32,13 @@ import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.http.HttpStatus; import org.springframework.http.converter.ByteArrayHttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.support.AllEncompassingFormHttpMessageConverter; import org.springframework.http.converter.xml.SourceHttpMessageConverter; +import org.springframework.ui.ModelMap; import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.context.request.ServletWebRequest; @@ -390,7 +392,9 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce return new ModelAndView(); } else { - ModelAndView mav = new ModelAndView().addAllObjects(mavContainer.getModel()); + ModelMap model = mavContainer.getModel(); + HttpStatus status = mavContainer.getStatus(); + ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, status); mav.setViewName(mavContainer.getViewName()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java index 01697dc701..3344d19809 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletAnnotationControllerHandlerMethodTests.java @@ -1742,6 +1742,18 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl assertEquals("view", response.getForwardedUrl()); } + @Test // SPR-14796 + public void modelAndViewWithStatusInExceptionHandler() throws Exception { + initServletWithControllers(ModelAndViewController.class); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/exception"); + MockHttpServletResponse response = new MockHttpServletResponse(); + getServlet().service(request, response); + + assertEquals(422, response.getStatus()); + assertEquals("view", response.getForwardedUrl()); + } + @Test public void httpHead() throws ServletException, IOException { initServletWithControllers(ResponseEntityController.class); @@ -3302,6 +3314,20 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl public ModelAndView methodWithHttpStatus(MyEntity object) { return new ModelAndView("view", new ModelMap(), HttpStatus.UNPROCESSABLE_ENTITY); } + + @RequestMapping("/exception") + public void raiseException() throws Exception { + throw new TestException(); + } + + @ExceptionHandler(TestException.class) + public ModelAndView handleException() { + return new ModelAndView("view", new ModelMap(), HttpStatus.UNPROCESSABLE_ENTITY); + } + + @SuppressWarnings("serial") + private static class TestException extends Exception { + } } }