Skip to content

Commit 73a7943

Browse files
committed
Support @ResponseStatus on controller type level
Issue: SPR-13547
1 parent 4b11835 commit 73a7943

File tree

4 files changed

+36
-9
lines changed

4 files changed

+36
-9
lines changed

spring-web/src/main/java/org/springframework/web/bind/annotation/ResponseStatus.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -44,6 +44,10 @@
4444
* preferable to use a {@link org.springframework.http.ResponseEntity} as
4545
* a return type and avoid the use of {@code @ResponseStatus} altogether.
4646
*
47+
* <p>Note that a controller class may also be annotated with
48+
* {@code @ResponseStatus} and is then inherited by all {@code @RequestMapping}
49+
* methods.
50+
*
4751
* @author Arjen Poutsma
4852
* @author Sam Brannen
4953
* @see org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@
2424

2525
import org.springframework.core.MethodParameter;
2626
import org.springframework.core.ResolvableType;
27+
import org.springframework.core.annotation.AnnotatedElementUtils;
2728
import org.springframework.http.HttpStatus;
2829
import org.springframework.util.ClassUtils;
2930
import org.springframework.util.StringUtils;
@@ -82,6 +83,9 @@ public ServletInvocableHandlerMethod(HandlerMethod handlerMethod) {
8283

8384
private void initResponseStatus() {
8485
ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
86+
if (annotation == null) {
87+
annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
88+
}
8589
if (annotation != null) {
8690
this.responseStatus = annotation.code();
8791
this.responseReason = annotation.reason();

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethodTests.java

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -92,6 +92,15 @@ public void invokeAndHandle_VoidWithComposedResponseStatus() throws Exception {
9292
assertEquals(HttpStatus.BAD_REQUEST.value(), this.response.getStatus());
9393
}
9494

95+
@Test
96+
public void invokeAndHandle_VoidWithTypeLevelResponseStatus() throws Exception {
97+
ServletInvocableHandlerMethod handlerMethod = getHandlerMethod(new ResponseStatusHandler(), "handle");
98+
handlerMethod.invokeAndHandle(this.webRequest, this.mavContainer);
99+
100+
assertTrue(this.mavContainer.isRequestHandled());
101+
assertEquals(HttpStatus.BAD_REQUEST.value(), this.response.getStatus());
102+
}
103+
95104
@Test
96105
public void invokeAndHandle_VoidWithHttpServletResponseArgument() throws Exception {
97106
this.argumentResolvers.addResolver(new ServletResponseMethodArgumentResolver());
@@ -169,7 +178,7 @@ public void wrapConcurrentResult_TypeLevelResponseBody() throws Exception {
169178
}
170179

171180
private void wrapConcurrentResult_ResponseBody(Object handler) throws Exception {
172-
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
181+
List<HttpMessageConverter<?>> converters = new ArrayList<>();
173182
converters.add(new StringHttpMessageConverter());
174183
this.returnValueHandlers.addHandler(new RequestResponseBodyMethodProcessor(converters));
175184
ServletInvocableHandlerMethod handlerMethod = getHandlerMethod(handler, "handle");
@@ -181,7 +190,7 @@ private void wrapConcurrentResult_ResponseBody(Object handler) throws Exception
181190

182191
@Test
183192
public void wrapConcurrentResult_ResponseEntity() throws Exception {
184-
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
193+
List<HttpMessageConverter<?>> converters = new ArrayList<>();
185194
converters.add(new StringHttpMessageConverter());
186195
this.returnValueHandlers.addHandler(new HttpEntityMethodProcessor(converters));
187196
ServletInvocableHandlerMethod handlerMethod = getHandlerMethod(new ResponseEntityHandler(), "handleDeferred");
@@ -195,7 +204,7 @@ public void wrapConcurrentResult_ResponseEntity() throws Exception {
195204

196205
@Test
197206
public void wrapConcurrentResult_ResponseEntityNullBody() throws Exception {
198-
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
207+
List<HttpMessageConverter<?>> converters = new ArrayList<>();
199208
converters.add(new StringHttpMessageConverter());
200209
List<Object> advice = Collections.singletonList(mock(ResponseBodyAdvice.class));
201210
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(converters, null, advice);
@@ -210,7 +219,7 @@ public void wrapConcurrentResult_ResponseEntityNullBody() throws Exception {
210219

211220
@Test
212221
public void wrapConcurrentResult_ResponseEntityNullReturnValue() throws Exception {
213-
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
222+
List<HttpMessageConverter<?>> converters = new ArrayList<>();
214223
converters.add(new StringHttpMessageConverter());
215224
List<Object> advice = Collections.singletonList(mock(ResponseBodyAdvice.class));
216225
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(converters, null, advice);
@@ -225,7 +234,7 @@ public void wrapConcurrentResult_ResponseEntityNullReturnValue() throws Exceptio
225234

226235
@Test
227236
public void wrapConcurrentResult_ResponseBodyEmitter() throws Exception {
228-
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
237+
List<HttpMessageConverter<?>> converters = new ArrayList<>();
229238
converters.add(new StringHttpMessageConverter());
230239
this.returnValueHandlers.addHandler(new ResponseBodyEmitterReturnValueHandler(converters));
231240
ServletInvocableHandlerMethod handlerMethod = getHandlerMethod(new AsyncHandler(), "handleWithEmitter");
@@ -272,6 +281,7 @@ private ServletInvocableHandlerMethod getHandlerMethod(Object controller,
272281
return handlerMethod;
273282
}
274283

284+
@SuppressWarnings("unused")
275285
@ResponseStatus
276286
@Retention(RetentionPolicy.RUNTIME)
277287
@interface ComposedResponseStatus {
@@ -311,6 +321,14 @@ public Object dynamicReturnValue(@RequestParam(required=false) String param) {
311321
}
312322
}
313323

324+
@SuppressWarnings("unused")
325+
@ResponseStatus(HttpStatus.BAD_REQUEST)
326+
private static class ResponseStatusHandler {
327+
328+
public void handle() {
329+
}
330+
}
331+
314332
private static class MethodLevelResponseBodyHandler {
315333

316334
@ResponseBody
@@ -324,7 +342,7 @@ public DeferredResult<String> handle() {
324342
private static class TypeLevelResponseBodyHandler {
325343

326344
public DeferredResult<String> handle() {
327-
return new DeferredResult<String>();
345+
return new DeferredResult<>();
328346
}
329347
}
330348

src/asciidoc/whats-new.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -653,6 +653,7 @@ Spring 4.3 also improves the caching abstraction as follows:
653653
=== Web Improvements
654654

655655
* New `@RestControllerAdvice` annotation combines `@ControllerAdvice` with `@ResponseBody`.
656+
* `@ResponseStatus` can be used on a controller type is inherited for all method.
656657
* `AsyncRestTemplate` supports request interception.
657658

658659
=== Testing Improvements

0 commit comments

Comments
 (0)