Commit 17919749 authored by Michele Mancioppi's avatar Michele Mancioppi Committed by Stephane Nicoll

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
parent c0a5e985
......@@ -22,9 +22,11 @@ import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ResponseStatusException;
......@@ -46,6 +48,7 @@ import org.springframework.web.server.ServerWebExchange;
*
* @author Brian Clozel
* @author Stephane Nicoll
* @author Michele Mancioppi
* @since 2.0.0
* @see ErrorAttributes
*/
......@@ -91,6 +94,14 @@ public class DefaultErrorAttributes implements ErrorAttributes {
if (error instanceof ResponseStatusException) {
return ((ResponseStatusException) error).getStatus();
}
ResponseStatus responseStatus = AnnotatedElementUtils
.findMergedAnnotation(error.getClass(), ResponseStatus.class);
if (responseStatus != null) {
return responseStatus.code();
}
return HttpStatus.INTERNAL_SERVER_ERROR;
}
......@@ -98,9 +109,18 @@ public class DefaultErrorAttributes implements ErrorAttributes {
if (error instanceof WebExchangeBindException) {
return error.getMessage();
}
if (error instanceof ResponseStatusException) {
return ((ResponseStatusException) error).getReason();
}
ResponseStatus responseStatus = AnnotatedElementUtils
.findMergedAnnotation(error.getClass(), ResponseStatus.class);
if (responseStatus != null) {
return responseStatus.reason();
}
return error.getMessage();
}
......
......@@ -35,6 +35,7 @@ import org.springframework.mock.web.server.MockServerWebExchange;
import org.springframework.validation.BindingResult;
import org.springframework.validation.MapBindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ResponseStatusException;
......@@ -90,6 +91,29 @@ public class DefaultErrorAttributesTests {
assertThat(attributes.get("status")).isEqualTo(500);
}
@Test
public void annotatedResponseStatusCode() {
Exception error = new CustomException();
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
Map<String, Object> attributes = this.errorAttributes
.getErrorAttributes(buildServerRequest(request, error), false);
assertThat(attributes.get("error"))
.isEqualTo(HttpStatus.I_AM_A_TEAPOT.getReasonPhrase());
assertThat(attributes.get("status")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.value());
}
@Test
public void annotatedResponseStatusCodeWithCustomReasonPhrase() {
Exception error = new Custom2Exception();
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
Map<String, Object> attributes = this.errorAttributes
.getErrorAttributes(buildServerRequest(request, error), false);
assertThat(attributes.get("error"))
.isEqualTo(HttpStatus.I_AM_A_TEAPOT.getReasonPhrase());
assertThat(attributes.get("status")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.value());
assertThat(attributes.get("message")).isEqualTo("Nope!");
}
@Test
public void includeStatusCode() {
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
......@@ -214,4 +238,14 @@ public class DefaultErrorAttributesTests {
return 42;
}
@ResponseStatus(HttpStatus.I_AM_A_TEAPOT)
private static class CustomException extends RuntimeException {
}
@ResponseStatus(value = HttpStatus.I_AM_A_TEAPOT, reason = "Nope!")
private static class Custom2Exception extends RuntimeException {
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment