diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java index ea241ff198f..d07c65d8a86 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java @@ -25,12 +25,14 @@ import java.lang.annotation.Target; import org.springframework.http.HttpStatus; /** - * Marks an exception class with the status code and reason that should be returned whenever said exception is thrown. + * Marks a method or exception class with the status code and reason that should be returned. The status code is applied + * to the HTTP response when the handler method is invoked, or whenever said exception is thrown. * * @author Arjen Poutsma + * @see org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver * @since 3.0 */ -@Target(ElementType.TYPE) +@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface ResponseStatus { diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index e712a60ff4f..e6b82218e90 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -75,6 +75,7 @@ import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.SessionAttributes; import org.springframework.web.bind.annotation.support.HandlerMethodInvoker; import org.springframework.web.bind.annotation.support.HandlerMethodResolver; @@ -672,6 +673,13 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen ExtendedModelMap implicitModel, ServletWebRequest webRequest) { + if (handlerMethod.isAnnotationPresent(ResponseStatus.class)) { + ResponseStatus responseStatus = handlerMethod.getAnnotation(ResponseStatus.class); + HttpServletResponse response = webRequest.getResponse(); + response.setStatus(responseStatus.value().value()); + responseArgumentUsed = true; + } + if (returnValue instanceof ModelAndView) { ModelAndView mav = (ModelAndView) returnValue; mav.getModelMap().mergeAttributes(implicitModel); diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java index 5ee4c427c6f..6689f77b9c6 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java @@ -54,6 +54,7 @@ import org.springframework.context.annotation.AnnotationConfigUtils; import org.springframework.core.MethodParameter; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; @@ -78,6 +79,7 @@ import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.bind.support.WebBindingInitializer; import org.springframework.web.context.WebApplicationContext; @@ -911,6 +913,17 @@ public class ServletAnnotationControllerTests { assertEquals("text", response.getContentAsString()); } + @Test + public void responseStatus() throws ServletException, IOException { + initServlet(ResponseStatusController.class); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/something"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("something", response.getContentAsString()); + assertEquals(201, response.getStatus()); + } + /* * Controllers */ @@ -1503,6 +1516,15 @@ public class ServletAnnotationControllerTests { } } + @Controller + public static class ResponseStatusController { + + @RequestMapping("/something") + @ResponseStatus(HttpStatus.CREATED) + public void handle(Writer writer) throws IOException { + writer.write("something"); + } + } public static class MyMessageConverter implements HttpMessageConverter {