Skip to content

Commit 1791974

Browse files
michele-mancioppisnicoll
authored andcommitted
Add support for @ResponseStatus in DefaultErrorAttributes
This commit adds support for @ResponseStatus in DefaultErrorAttributes mimicking the semantics of @ResponseStatus in SpringMVC. Throwables annotated with @ResponseStatus handled by DefaultErrorAttributes will result in the following error attributes: * 'status' set as the return value of the HttpStatus#value() defined as @ResponseStatus#value() * 'error' set to the default reason phrase of the HttpStatus defined as @ResponseStatus#value() * 'message' defined as the value of @ResponseStatus#reason(), or the default HttpStatus's reason phrase if left unspecified See gh-14744
1 parent c0a5e98 commit 1791974

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed

spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import java.util.LinkedHashMap;
2323
import java.util.Map;
2424

25+
import org.springframework.core.annotation.AnnotatedElementUtils;
2526
import org.springframework.http.HttpStatus;
2627
import org.springframework.validation.BindingResult;
2728
import org.springframework.validation.ObjectError;
29+
import org.springframework.web.bind.annotation.ResponseStatus;
2830
import org.springframework.web.bind.support.WebExchangeBindException;
2931
import org.springframework.web.reactive.function.server.ServerRequest;
3032
import org.springframework.web.server.ResponseStatusException;
@@ -46,6 +48,7 @@
4648
*
4749
* @author Brian Clozel
4850
* @author Stephane Nicoll
51+
* @author Michele Mancioppi
4952
* @since 2.0.0
5053
* @see ErrorAttributes
5154
*/
@@ -91,16 +94,33 @@ private HttpStatus determineHttpStatus(Throwable error) {
9194
if (error instanceof ResponseStatusException) {
9295
return ((ResponseStatusException) error).getStatus();
9396
}
97+
98+
ResponseStatus responseStatus = AnnotatedElementUtils
99+
.findMergedAnnotation(error.getClass(), ResponseStatus.class);
100+
101+
if (responseStatus != null) {
102+
return responseStatus.code();
103+
}
104+
94105
return HttpStatus.INTERNAL_SERVER_ERROR;
95106
}
96107

97108
private String determineMessage(Throwable error) {
98109
if (error instanceof WebExchangeBindException) {
99110
return error.getMessage();
100111
}
112+
101113
if (error instanceof ResponseStatusException) {
102114
return ((ResponseStatusException) error).getReason();
103115
}
116+
117+
ResponseStatus responseStatus = AnnotatedElementUtils
118+
.findMergedAnnotation(error.getClass(), ResponseStatus.class);
119+
120+
if (responseStatus != null) {
121+
return responseStatus.reason();
122+
}
123+
104124
return error.getMessage();
105125
}
106126

spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
import org.springframework.validation.BindingResult;
3636
import org.springframework.validation.MapBindingResult;
3737
import org.springframework.validation.ObjectError;
38+
import org.springframework.web.bind.annotation.ResponseStatus;
3839
import org.springframework.web.bind.support.WebExchangeBindException;
3940
import org.springframework.web.reactive.function.server.ServerRequest;
4041
import org.springframework.web.server.ResponseStatusException;
@@ -90,6 +91,29 @@ public void defaultStatusCode() {
9091
assertThat(attributes.get("status")).isEqualTo(500);
9192
}
9293

94+
@Test
95+
public void annotatedResponseStatusCode() {
96+
Exception error = new CustomException();
97+
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
98+
Map<String, Object> attributes = this.errorAttributes
99+
.getErrorAttributes(buildServerRequest(request, error), false);
100+
assertThat(attributes.get("error"))
101+
.isEqualTo(HttpStatus.I_AM_A_TEAPOT.getReasonPhrase());
102+
assertThat(attributes.get("status")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.value());
103+
}
104+
105+
@Test
106+
public void annotatedResponseStatusCodeWithCustomReasonPhrase() {
107+
Exception error = new Custom2Exception();
108+
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
109+
Map<String, Object> attributes = this.errorAttributes
110+
.getErrorAttributes(buildServerRequest(request, error), false);
111+
assertThat(attributes.get("error"))
112+
.isEqualTo(HttpStatus.I_AM_A_TEAPOT.getReasonPhrase());
113+
assertThat(attributes.get("status")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.value());
114+
assertThat(attributes.get("message")).isEqualTo("Nope!");
115+
}
116+
93117
@Test
94118
public void includeStatusCode() {
95119
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
@@ -214,4 +238,14 @@ public int method(String firstParam) {
214238
return 42;
215239
}
216240

241+
@ResponseStatus(HttpStatus.I_AM_A_TEAPOT)
242+
private static class CustomException extends RuntimeException {
243+
244+
}
245+
246+
@ResponseStatus(value = HttpStatus.I_AM_A_TEAPOT, reason = "Nope!")
247+
private static class Custom2Exception extends RuntimeException {
248+
249+
}
250+
217251
}

0 commit comments

Comments
 (0)