From aead3a7c447bce9d9a2452169b79715107fa33a3 Mon Sep 17 00:00:00 2001 From: Dmytro Nosan Date: Fri, 24 Jan 2020 12:28:46 +0200 Subject: [PATCH 1/2] Handle message of @ResponseStatus-annotated exception with WebFlux See gh-19901 --- .../error/DefaultErrorAttributes.java | 3 ++- .../error/DefaultErrorAttributesTests.java | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java index eebc8ab8bba..04a0bf2f81d 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,6 +24,7 @@ import java.util.Map; import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.http.HttpStatus; +import org.springframework.util.StringUtils; import org.springframework.validation.BindingResult; import org.springframework.validation.ObjectError; import org.springframework.web.bind.annotation.ResponseStatus; diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java index 5a3ee8a8b44..e47ace975b9 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -89,6 +89,18 @@ public class DefaultErrorAttributesTests { Map attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error), false); assertThat(attributes.get("error")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.getReasonPhrase()); + assertThat(attributes.get("message")).isEqualTo(""); + assertThat(attributes.get("status")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.value()); + } + + @Test + void annotatedResponseStatusCodeWithExceptionMessage() { + Exception error = new CustomException("Test Message"); + MockServerHttpRequest request = MockServerHttpRequest.get("/test").build(); + Map attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error), + false); + assertThat(attributes.get("error")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.getReasonPhrase()); + assertThat(attributes.get("message")).isEqualTo("Test Message"); assertThat(attributes.get("status")).isEqualTo(HttpStatus.I_AM_A_TEAPOT.value()); } @@ -218,6 +230,13 @@ public class DefaultErrorAttributesTests { @ResponseStatus(HttpStatus.I_AM_A_TEAPOT) private static class CustomException extends RuntimeException { + CustomException() { + } + + CustomException(String message) { + super(message); + } + } @ResponseStatus(value = HttpStatus.I_AM_A_TEAPOT, reason = "Nope!") From 12b644d73cfea40f5d3a3f05c586112a8fec69ce Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 3 Feb 2020 18:20:48 +0100 Subject: [PATCH 2/2] Polish contribution See gh-19901 --- .../reactive/error/DefaultErrorAttributes.java | 18 ++++++++---------- .../error/DefaultErrorAttributesTests.java | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java index 04a0bf2f81d..901c459c023 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributes.java @@ -81,39 +81,37 @@ public class DefaultErrorAttributes implements ErrorAttributes { errorAttributes.put("timestamp", new Date()); errorAttributes.put("path", request.path()); Throwable error = getError(request); - HttpStatus errorStatus = determineHttpStatus(error); + ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(error.getClass(), + ResponseStatus.class); + HttpStatus errorStatus = determineHttpStatus(error, responseStatus); errorAttributes.put("status", errorStatus.value()); errorAttributes.put("error", errorStatus.getReasonPhrase()); - errorAttributes.put("message", determineMessage(error)); + errorAttributes.put("message", determineMessage(error, responseStatus)); handleException(errorAttributes, determineException(error), includeStackTrace); return errorAttributes; } - private HttpStatus determineHttpStatus(Throwable error) { + private HttpStatus determineHttpStatus(Throwable error, ResponseStatus responseStatus) { 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; } - private String determineMessage(Throwable error) { + private String determineMessage(Throwable error, ResponseStatus responseStatus) { 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) { + if (responseStatus != null && StringUtils.hasText(responseStatus.reason())) { return responseStatus.reason(); } - return error.getMessage(); + return (error.getMessage() != null) ? error.getMessage() : ""; } private Throwable determineException(Throwable error) { diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java index e47ace975b9..fef4c4391a1 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/web/reactive/error/DefaultErrorAttributesTests.java @@ -94,7 +94,7 @@ public class DefaultErrorAttributesTests { } @Test - void annotatedResponseStatusCodeWithExceptionMessage() { + public void annotatedResponseStatusCodeWithExceptionMessage() { Exception error = new CustomException("Test Message"); MockServerHttpRequest request = MockServerHttpRequest.get("/test").build(); Map attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error),