Separate server properties for message and errors
Prior to this commit, there was a property server.error.include-details that allowed configuration of the message and errors attributes in a server error response. This commit separates the control of the message and errors attributes into two separate properties named server.error.include-message and server.error.include-binding-errors. When the message attribute is excluded from a servlet response, the value is changed from a hard-coded text value to an empty value. Fixes gh-20505
This commit is contained in:
parent
18a9a229b1
commit
a30740f8d2
|
@ -53,26 +53,38 @@ public class ManagementErrorEndpoint {
|
|||
@RequestMapping("${server.error.path:${error.path:/error}}")
|
||||
@ResponseBody
|
||||
public Map<String, Object> invoke(ServletWebRequest request) {
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace(request), includeDetails(request));
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace(request), includeMessage(request),
|
||||
includeBindingErrors(request));
|
||||
}
|
||||
|
||||
private boolean includeStackTrace(ServletWebRequest request) {
|
||||
switch (this.errorProperties.getIncludeStacktrace()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_TRACE_PARAM:
|
||||
case ON_PARAM:
|
||||
return getBooleanParameter(request, "trace");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean includeDetails(ServletWebRequest request) {
|
||||
switch (this.errorProperties.getIncludeDetails()) {
|
||||
private boolean includeMessage(ServletWebRequest request) {
|
||||
switch (this.errorProperties.getIncludeMessage()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_DETAILS_PARAM:
|
||||
return getBooleanParameter(request, "details");
|
||||
case ON_PARAM:
|
||||
return getBooleanParameter(request, "message");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean includeBindingErrors(ServletWebRequest request) {
|
||||
switch (this.errorProperties.getIncludeBindingErrors()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_PARAM:
|
||||
return getBooleanParameter(request, "errors");
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -51,16 +51,16 @@ class ManagementErrorEndpointTests {
|
|||
void errorResponseNeverDetails() {
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(new MockHttpServletRequest()));
|
||||
assertThat(response).containsEntry("message", "An error occurred while processing the request");
|
||||
assertThat(response).containsEntry("message", "");
|
||||
assertThat(response).doesNotContainKey("trace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseAlwaysDetails() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ALWAYS);
|
||||
this.errorProperties.setIncludeDetails(ErrorProperties.IncludeDetails.ALWAYS);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ALWAYS);
|
||||
this.request.addParameter("trace", "false");
|
||||
this.request.addParameter("details", "false");
|
||||
this.request.addParameter("message", "false");
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).containsEntry("message", "test exception");
|
||||
|
@ -70,20 +70,20 @@ class ManagementErrorEndpointTests {
|
|||
|
||||
@Test
|
||||
void errorResponseParamsAbsent() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM);
|
||||
this.errorProperties.setIncludeDetails(ErrorProperties.IncludeDetails.ON_DETAILS_PARAM);
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ON_PARAM);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).containsEntry("message", "An error occurred while processing the request");
|
||||
assertThat(response).containsEntry("message", "");
|
||||
assertThat(response).doesNotContainKey("trace");
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorResponseParamsTrue() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM);
|
||||
this.errorProperties.setIncludeDetails(ErrorProperties.IncludeDetails.ON_DETAILS_PARAM);
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ON_PARAM);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.request.addParameter("trace", "true");
|
||||
this.request.addParameter("details", "true");
|
||||
this.request.addParameter("message", "true");
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).containsEntry("message", "test exception");
|
||||
|
@ -93,13 +93,13 @@ class ManagementErrorEndpointTests {
|
|||
|
||||
@Test
|
||||
void errorResponseParamsFalse() {
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ON_TRACE_PARAM);
|
||||
this.errorProperties.setIncludeDetails(ErrorProperties.IncludeDetails.ON_DETAILS_PARAM);
|
||||
this.errorProperties.setIncludeStacktrace(ErrorProperties.IncludeStacktrace.ON_PARAM);
|
||||
this.errorProperties.setIncludeMessage(ErrorProperties.IncludeAttribute.ON_PARAM);
|
||||
this.request.addParameter("trace", "false");
|
||||
this.request.addParameter("details", "false");
|
||||
this.request.addParameter("message", "false");
|
||||
ManagementErrorEndpoint endpoint = new ManagementErrorEndpoint(this.errorAttributes, this.errorProperties);
|
||||
Map<String, Object> response = endpoint.invoke(new ServletWebRequest(this.request));
|
||||
assertThat(response).containsEntry("message", "An error occurred while processing the request");
|
||||
assertThat(response).containsEntry("message", "");
|
||||
assertThat(response).doesNotContainKey("trace");
|
||||
}
|
||||
|
||||
|
|
|
@ -67,14 +67,14 @@ class WebMvcEndpointChildContextConfigurationIntegrationTests {
|
|||
ClientResponse response = client.get().uri("actuator/fail").accept(MediaType.APPLICATION_JSON).exchange()
|
||||
.block();
|
||||
Map<Object, Object> body = response.bodyToMono(Map.class).block();
|
||||
assertThat(body).containsEntry("message", "An error occurred while processing the request");
|
||||
assertThat(body).containsEntry("message", "");
|
||||
assertThat(body).doesNotContainKey("trace");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void errorPageAndErrorControllerIncludeDetails() {
|
||||
this.runner.withPropertyValues("server.error.include-stacktrace=always", "server.error.include-details=always")
|
||||
this.runner.withPropertyValues("server.error.include-stacktrace=always", "server.error.include-message=always")
|
||||
.run((context) -> {
|
||||
String port = context.getEnvironment().getProperty("local.management.port");
|
||||
WebClient client = WebClient.create("http://localhost:" + port);
|
||||
|
|
|
@ -412,7 +412,7 @@ public abstract class AbstractWebEndpointIntegrationTests<T extends Configurable
|
|||
contextCustomizer.accept(applicationContext);
|
||||
Map<String, Object> properties = new HashMap<>();
|
||||
properties.put("endpointPath", endpointPath);
|
||||
properties.put("server.error.include-details", "always");
|
||||
properties.put("server.error.include-message", "always");
|
||||
applicationContext.getEnvironment().getPropertySources().addLast(new MapPropertySource("test", properties));
|
||||
applicationContext.refresh();
|
||||
try {
|
||||
|
|
|
@ -46,9 +46,14 @@ public class ErrorProperties {
|
|||
private IncludeStacktrace includeStacktrace = IncludeStacktrace.NEVER;
|
||||
|
||||
/**
|
||||
* When to include "message" and "errors" attributes.
|
||||
* When to include "message" attribute.
|
||||
*/
|
||||
private IncludeDetails includeDetails = IncludeDetails.NEVER;
|
||||
private IncludeAttribute includeMessage = IncludeAttribute.NEVER;
|
||||
|
||||
/**
|
||||
* When to include "errors" attribute.
|
||||
*/
|
||||
private IncludeAttribute includeBindingErrors = IncludeAttribute.NEVER;
|
||||
|
||||
private final Whitelabel whitelabel = new Whitelabel();
|
||||
|
||||
|
@ -76,12 +81,20 @@ public class ErrorProperties {
|
|||
this.includeStacktrace = includeStacktrace;
|
||||
}
|
||||
|
||||
public IncludeDetails getIncludeDetails() {
|
||||
return this.includeDetails;
|
||||
public IncludeAttribute getIncludeMessage() {
|
||||
return this.includeMessage;
|
||||
}
|
||||
|
||||
public void setIncludeDetails(IncludeDetails includeDetails) {
|
||||
this.includeDetails = includeDetails;
|
||||
public void setIncludeMessage(IncludeAttribute includeMessage) {
|
||||
this.includeMessage = includeMessage;
|
||||
}
|
||||
|
||||
public IncludeAttribute getIncludeBindingErrors() {
|
||||
return this.includeMessage;
|
||||
}
|
||||
|
||||
public void setIncludeBindingErrors(IncludeAttribute includeMessage) {
|
||||
this.includeMessage = includeMessage;
|
||||
}
|
||||
|
||||
public Whitelabel getWhitelabel() {
|
||||
|
@ -96,39 +109,56 @@ public class ErrorProperties {
|
|||
/**
|
||||
* Never add stacktrace information.
|
||||
*/
|
||||
NEVER,
|
||||
NEVER(IncludeAttribute.NEVER),
|
||||
|
||||
/**
|
||||
* Always add stacktrace information.
|
||||
*/
|
||||
ALWAYS,
|
||||
ALWAYS(IncludeAttribute.ALWAYS),
|
||||
|
||||
/**
|
||||
* Add error attribute when the appropriate request parameter is "true".
|
||||
*/
|
||||
ON_PARAM(IncludeAttribute.ON_PARAM),
|
||||
|
||||
/**
|
||||
* Add stacktrace information when the "trace" request parameter is "true".
|
||||
* @deprecated since 2.3.0 in favor of {@link #ON_PARAM}
|
||||
*/
|
||||
ON_TRACE_PARAM
|
||||
@Deprecated
|
||||
ON_TRACE_PARAM(IncludeAttribute.ON_PARAM);
|
||||
|
||||
private final IncludeAttribute include;
|
||||
|
||||
IncludeStacktrace(IncludeAttribute include) {
|
||||
this.include = include;
|
||||
}
|
||||
|
||||
public IncludeAttribute getInclude() {
|
||||
return this.include;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Include error details attributes options.
|
||||
* Include error attributes options.
|
||||
*/
|
||||
public enum IncludeDetails {
|
||||
public enum IncludeAttribute {
|
||||
|
||||
/**
|
||||
* Never add error detail information.
|
||||
* Never add error attribute.
|
||||
*/
|
||||
NEVER,
|
||||
|
||||
/**
|
||||
* Always add error detail information.
|
||||
* Always add error attribute.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Add error details information when the "details" request parameter is "true".
|
||||
* Add error attribute when the appropriate request parameter is "true".
|
||||
*/
|
||||
ON_DETAILS_PARAM
|
||||
ON_PARAM
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -134,24 +134,26 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
|||
* @param includeStackTrace whether to include the error stacktrace information
|
||||
* @return the error attributes as a Map
|
||||
* @deprecated since 2.3.0 in favor of
|
||||
* {@link #getErrorAttributes(ServerRequest, boolean, boolean)}
|
||||
* {@link #getErrorAttributes(ServerRequest, boolean, boolean, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace, false);
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace, false, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the error attributes from the current request, to be used to populate error
|
||||
* views or JSON payloads.
|
||||
* @param request the source request
|
||||
* @param includeStackTrace whether to include the error stacktrace information
|
||||
* @param includeDetails whether to include message and errors attributes
|
||||
* @param includeStackTrace whether to include the stacktrace attribute
|
||||
* @param includeMessage whether to include the message attribute
|
||||
* @param includeBindingErrors whether to include the errors attribute
|
||||
* @return the error attributes as a Map
|
||||
*/
|
||||
protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace,
|
||||
boolean includeDetails) {
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace, includeDetails);
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
return this.errorAttributes.getErrorAttributes(request, includeStackTrace, includeMessage,
|
||||
includeBindingErrors);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -173,13 +175,23 @@ public abstract class AbstractErrorWebExceptionHandler implements ErrorWebExcept
|
|||
}
|
||||
|
||||
/**
|
||||
* Check whether the details attribute has been set on the given request.
|
||||
* Check whether the message attribute has been set on the given request.
|
||||
* @param request the source request
|
||||
* @return {@code true} if the error details have been requested, {@code false}
|
||||
* @return {@code true} if the message attribute has been requested, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
protected boolean isDetailsEnabled(ServerRequest request) {
|
||||
return getBooleanParameter(request, "details");
|
||||
protected boolean isMessageEnabled(ServerRequest request) {
|
||||
return getBooleanParameter(request, "message");
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the errors attribute has been set on the given request.
|
||||
* @param request the source request
|
||||
* @return {@code true} if the errors attribute has been requested, {@code false}
|
||||
* otherwise
|
||||
*/
|
||||
protected boolean isBindingErrorsEnabled(ServerRequest request) {
|
||||
return getBooleanParameter(request, "errors");
|
||||
}
|
||||
|
||||
private boolean getBooleanParameter(ServerRequest request, String parameterName) {
|
||||
|
|
|
@ -114,8 +114,10 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
|||
*/
|
||||
protected Mono<ServerResponse> renderErrorView(ServerRequest request) {
|
||||
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.TEXT_HTML);
|
||||
boolean includeDetails = isIncludeDetails(request, MediaType.TEXT_HTML);
|
||||
Map<String, Object> error = getErrorAttributes(request, includeStackTrace, includeDetails);
|
||||
boolean includeMessage = isIncludeMessage(request, MediaType.TEXT_HTML);
|
||||
boolean includeBindingErrors = isIncludeBindingErrors(request, MediaType.TEXT_HTML);
|
||||
Map<String, Object> error = getErrorAttributes(request, includeStackTrace, includeMessage,
|
||||
includeBindingErrors);
|
||||
int errorStatus = getHttpStatus(error);
|
||||
ServerResponse.BodyBuilder responseBody = ServerResponse.status(errorStatus).contentType(TEXT_HTML_UTF8);
|
||||
return Flux.just(getData(errorStatus).toArray(new String[] {}))
|
||||
|
@ -143,8 +145,10 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
|||
*/
|
||||
protected Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
|
||||
boolean includeStackTrace = isIncludeStackTrace(request, MediaType.ALL);
|
||||
boolean includeDetails = isIncludeDetails(request, MediaType.ALL);
|
||||
Map<String, Object> error = getErrorAttributes(request, includeStackTrace, includeDetails);
|
||||
boolean includeMessage = isIncludeMessage(request, MediaType.ALL);
|
||||
boolean includeBindingErrors = isIncludeBindingErrors(request, MediaType.ALL);
|
||||
Map<String, Object> error = getErrorAttributes(request, includeStackTrace, includeMessage,
|
||||
includeBindingErrors);
|
||||
return ServerResponse.status(getHttpStatus(error)).contentType(MediaType.APPLICATION_JSON)
|
||||
.body(BodyInserters.fromValue(error));
|
||||
}
|
||||
|
@ -155,10 +159,12 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
|||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the stacktrace attribute should be included
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected boolean isIncludeStackTrace(ServerRequest request, MediaType produces) {
|
||||
switch (this.errorProperties.getIncludeStacktrace()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_PARAM:
|
||||
case ON_TRACE_PARAM:
|
||||
return isTraceEnabled(request);
|
||||
default:
|
||||
|
@ -167,17 +173,34 @@ public class DefaultErrorWebExceptionHandler extends AbstractErrorWebExceptionHa
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine if the message and errors attributes should be included.
|
||||
* Determine if the message attribute should be included.
|
||||
* @param request the source request
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the message and errors attributes should be included
|
||||
* @return if the message attribute should be included
|
||||
*/
|
||||
protected boolean isIncludeDetails(ServerRequest request, MediaType produces) {
|
||||
switch (this.errorProperties.getIncludeDetails()) {
|
||||
protected boolean isIncludeMessage(ServerRequest request, MediaType produces) {
|
||||
switch (this.errorProperties.getIncludeMessage()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_DETAILS_PARAM:
|
||||
return isDetailsEnabled(request);
|
||||
case ON_PARAM:
|
||||
return isMessageEnabled(request);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the errors attribute should be included.
|
||||
* @param request the source request
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the errors attribute should be included
|
||||
*/
|
||||
protected boolean isIncludeBindingErrors(ServerRequest request, MediaType produces) {
|
||||
switch (this.errorProperties.getIncludeBindingErrors()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_PARAM:
|
||||
return isBindingErrorsEnabled(request);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -74,25 +74,30 @@ public abstract class AbstractErrorController implements ErrorController {
|
|||
* @param includeStackTrace if stack trace elements should be included
|
||||
* @return the error attributes
|
||||
* @deprecated since 2.3.0 in favor of
|
||||
* {@link #getErrorAttributes(HttpServletRequest, boolean, boolean)}
|
||||
* {@link #getErrorAttributes(HttpServletRequest, boolean, boolean, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace) {
|
||||
return getErrorAttributes(request, includeStackTrace, false);
|
||||
return getErrorAttributes(request, includeStackTrace, false, false);
|
||||
}
|
||||
|
||||
protected Map<String, Object> getErrorAttributes(HttpServletRequest request, boolean includeStackTrace,
|
||||
boolean includeDetails) {
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
WebRequest webRequest = new ServletWebRequest(request);
|
||||
return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace, includeDetails);
|
||||
return this.errorAttributes.getErrorAttributes(webRequest, includeStackTrace, includeMessage,
|
||||
includeBindingErrors);
|
||||
}
|
||||
|
||||
protected boolean getTraceParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "trace");
|
||||
}
|
||||
|
||||
protected boolean getDetailsParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "details");
|
||||
protected boolean getMessageParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "message");
|
||||
}
|
||||
|
||||
protected boolean getErrorsParameter(HttpServletRequest request) {
|
||||
return getBooleanParameter(request, "errors");
|
||||
}
|
||||
|
||||
protected boolean getBooleanParameter(HttpServletRequest request, String parameterName) {
|
||||
|
|
|
@ -88,7 +88,8 @@ public class BasicErrorController extends AbstractErrorController {
|
|||
public ModelAndView errorHtml(HttpServletRequest request, HttpServletResponse response) {
|
||||
HttpStatus status = getStatus(request);
|
||||
Map<String, Object> model = Collections.unmodifiableMap(getErrorAttributes(request,
|
||||
isIncludeStackTrace(request, MediaType.TEXT_HTML), isIncludeDetails(request, MediaType.TEXT_HTML)));
|
||||
isIncludeStackTrace(request, MediaType.TEXT_HTML), isIncludeMessage(request, MediaType.TEXT_HTML),
|
||||
isIncludeBindingErrors(request, MediaType.TEXT_HTML)));
|
||||
response.setStatus(status.value());
|
||||
ModelAndView modelAndView = resolveErrorView(request, response, status, model);
|
||||
return (modelAndView != null) ? modelAndView : new ModelAndView("error", model);
|
||||
|
@ -101,7 +102,7 @@ public class BasicErrorController extends AbstractErrorController {
|
|||
return new ResponseEntity<>(status);
|
||||
}
|
||||
Map<String, Object> body = getErrorAttributes(request, isIncludeStackTrace(request, MediaType.ALL),
|
||||
isIncludeDetails(request, MediaType.ALL));
|
||||
isIncludeMessage(request, MediaType.ALL), isIncludeBindingErrors(request, MediaType.TEXT_HTML));
|
||||
return new ResponseEntity<>(body, status);
|
||||
}
|
||||
|
||||
|
@ -117,10 +118,12 @@ public class BasicErrorController extends AbstractErrorController {
|
|||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the stacktrace attribute should be included
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
protected boolean isIncludeStackTrace(HttpServletRequest request, MediaType produces) {
|
||||
switch (getErrorProperties().getIncludeStacktrace()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_PARAM:
|
||||
case ON_TRACE_PARAM:
|
||||
return getTraceParameter(request);
|
||||
default:
|
||||
|
@ -129,17 +132,34 @@ public class BasicErrorController extends AbstractErrorController {
|
|||
}
|
||||
|
||||
/**
|
||||
* Determine if the error details attributes should be included.
|
||||
* Determine if the message attribute should be included.
|
||||
* @param request the source request
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the error details attributes should be included
|
||||
* @return if the message attribute should be included
|
||||
*/
|
||||
protected boolean isIncludeDetails(HttpServletRequest request, MediaType produces) {
|
||||
switch (getErrorProperties().getIncludeDetails()) {
|
||||
protected boolean isIncludeMessage(HttpServletRequest request, MediaType produces) {
|
||||
switch (getErrorProperties().getIncludeMessage()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_DETAILS_PARAM:
|
||||
return getDetailsParameter(request);
|
||||
case ON_PARAM:
|
||||
return getMessageParameter(request);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the errors attribute should be included.
|
||||
* @param request the source request
|
||||
* @param produces the media type produced (or {@code MediaType.ALL})
|
||||
* @return if the errors attribute should be included
|
||||
*/
|
||||
protected boolean isIncludeBindingErrors(HttpServletRequest request, MediaType produces) {
|
||||
switch (getErrorProperties().getIncludeMessage()) {
|
||||
case ALWAYS:
|
||||
return true;
|
||||
case ON_PARAM:
|
||||
return getErrorsParameter(request);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,11 @@
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "server.error.include-details",
|
||||
"name": "server.error.include-binding-errors",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
"name": "server.error.include-message",
|
||||
"defaultValue": "never"
|
||||
},
|
||||
{
|
||||
|
|
|
@ -99,7 +99,7 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
|
||||
@Test
|
||||
void htmlError() {
|
||||
this.contextRunner.withPropertyValues("server.error.include-details=always").run((context) -> {
|
||||
this.contextRunner.withPropertyValues("server.error.include-message=always").run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
String body = client.get().uri("/").accept(MediaType.TEXT_HTML).exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectHeader().contentType(TEXT_HTML_UTF8)
|
||||
|
@ -116,26 +116,43 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
.isBadRequest().expectBody().jsonPath("status").isEqualTo("400").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()).jsonPath("path").isEqualTo(("/bind"))
|
||||
.jsonPath("exception").doesNotExist().jsonPath("errors").doesNotExist().jsonPath("message")
|
||||
.isNotEmpty().jsonPath("requestId").isEqualTo(this.logIdFilter.getLogId());
|
||||
.isEmpty().jsonPath("requestId").isEqualTo(this.logIdFilter.getLogId());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void bindingResultErrorIncludeDetails() {
|
||||
this.contextRunner.withPropertyValues("server.error.include-details=on-details-param").run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.post().uri("/bind?details=true").contentType(MediaType.APPLICATION_JSON).bodyValue("{}").exchange()
|
||||
.expectStatus().isBadRequest().expectBody().jsonPath("status").isEqualTo("400").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase()).jsonPath("path").isEqualTo(("/bind"))
|
||||
.jsonPath("exception").doesNotExist().jsonPath("errors").isArray().jsonPath("message").isNotEmpty()
|
||||
.jsonPath("requestId").isEqualTo(this.logIdFilter.getLogId());
|
||||
});
|
||||
void bindingResultErrorIncludeMessageAndErrors() {
|
||||
this.contextRunner.withPropertyValues("server.error.include-message=on-param",
|
||||
"server.error.include-binding-errors=on-param").run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.post().uri("/bind?message=true&errors=true").contentType(MediaType.APPLICATION_JSON)
|
||||
.bodyValue("{}").exchange().expectStatus().isBadRequest().expectBody().jsonPath("status")
|
||||
.isEqualTo("400").jsonPath("error").isEqualTo(HttpStatus.BAD_REQUEST.getReasonPhrase())
|
||||
.jsonPath("path").isEqualTo(("/bind")).jsonPath("exception").doesNotExist()
|
||||
.jsonPath("errors").isArray().jsonPath("message").isNotEmpty().jsonPath("requestId")
|
||||
.isEqualTo(this.logIdFilter.getLogId());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void includeStackTraceOnTraceParam() {
|
||||
this.contextRunner.withPropertyValues("server.error.include-exception=true",
|
||||
"server.error.include-stacktrace=on-trace-param").run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.get().uri("/?trace=true").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody().jsonPath("status")
|
||||
.isEqualTo("500").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()).jsonPath("exception")
|
||||
.isEqualTo(IllegalStateException.class.getName()).jsonPath("trace").exists()
|
||||
.jsonPath("requestId").isEqualTo(this.logIdFilter.getLogId());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void includeStackTraceOnParam() {
|
||||
this.contextRunner.withPropertyValues("server.error.include-exception=true",
|
||||
"server.error.include-stacktrace=on-trace-param").run((context) -> {
|
||||
this.contextRunner
|
||||
.withPropertyValues("server.error.include-exception=true", "server.error.include-stacktrace=on-param")
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.get().uri("/?trace=true").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody().jsonPath("status")
|
||||
|
@ -177,11 +194,12 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void includeDetailsOnParam() {
|
||||
this.contextRunner.withPropertyValues("server.error.include-exception=true",
|
||||
"server.error.include-details=on-details-param").run((context) -> {
|
||||
void includeMessageOnParam() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("server.error.include-exception=true", "server.error.include-message=on-param")
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.get().uri("/?details=true").exchange().expectStatus()
|
||||
client.get().uri("/?message=true").exchange().expectStatus()
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR).expectBody().jsonPath("status")
|
||||
.isEqualTo("500").jsonPath("error")
|
||||
.isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()).jsonPath("exception")
|
||||
|
@ -191,9 +209,9 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void alwaysIncludeDetails() {
|
||||
void alwaysIncludeMessage() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("server.error.include-exception=true", "server.error.include-details=always")
|
||||
.withPropertyValues("server.error.include-exception=true", "server.error.include-message=always")
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.get().uri("/?trace=false").exchange().expectStatus()
|
||||
|
@ -206,9 +224,9 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void neverIncludeDetails() {
|
||||
void neverIncludeMessage() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("server.error.include-exception=true", "server.error.include-details=never")
|
||||
.withPropertyValues("server.error.include-exception=true", "server.error.include-message=never")
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
client.get().uri("/?trace=true").exchange().expectStatus()
|
||||
|
@ -235,7 +253,7 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
void defaultErrorView() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/",
|
||||
"server.error.include-stacktrace=always", "server.error.include-details=always")
|
||||
"server.error.include-stacktrace=always", "server.error.include-message=always")
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
String body = client.get().uri("/").accept(MediaType.TEXT_HTML).exchange().expectStatus()
|
||||
|
@ -250,7 +268,7 @@ class DefaultErrorWebExceptionHandlerIntegrationTests {
|
|||
@Test
|
||||
void escapeHtmlInDefaultErrorView() {
|
||||
this.contextRunner
|
||||
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/", "server.error.include-details=always")
|
||||
.withPropertyValues("spring.mustache.prefix=classpath:/unknown/", "server.error.include-message=always")
|
||||
.run((context) -> {
|
||||
WebTestClient client = getWebClient(context);
|
||||
String body = client.get().uri("/html").accept(MediaType.TEXT_HTML).exchange().expectStatus()
|
||||
|
|
|
@ -66,7 +66,8 @@ class DefaultErrorWebExceptionHandlerTests {
|
|||
ResourceProperties resourceProperties = new ResourceProperties();
|
||||
ErrorProperties errorProperties = new ErrorProperties();
|
||||
ApplicationContext context = new AnnotationConfigReactiveWebApplicationContext();
|
||||
given(errorAttributes.getErrorAttributes(any(), anyBoolean(), anyBoolean())).willReturn(getErrorAttributes());
|
||||
given(errorAttributes.getErrorAttributes(any(), anyBoolean(), anyBoolean(), anyBoolean()))
|
||||
.willReturn(getErrorAttributes());
|
||||
DefaultErrorWebExceptionHandler exceptionHandler = new DefaultErrorWebExceptionHandler(errorAttributes,
|
||||
resourceProperties, errorProperties, context);
|
||||
setupViewResolver(exceptionHandler);
|
||||
|
|
|
@ -88,57 +88,63 @@ class BasicErrorControllerIntegrationTests {
|
|||
void testErrorForMachineClientDefault() {
|
||||
load();
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("?trace=true"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", null,
|
||||
"An error occurred while processing the request", "/");
|
||||
assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", null, "", "/");
|
||||
assertThat(entity.getBody().containsKey("exception")).isFalse();
|
||||
assertThat(entity.getBody().containsKey("trace")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientWithParamsTrue() {
|
||||
void testErrorForMachineClientWithTraceParamsTrue() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-trace-param",
|
||||
"--server.error.include-details=on-details-param");
|
||||
exceptionWithStackTraceAndDetails("?trace=true&details=true");
|
||||
"--server.error.include-message=on-param");
|
||||
exceptionWithStackTraceAndMessage("?trace=true&message=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientWithParamsTrue() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-param",
|
||||
"--server.error.include-message=on-param");
|
||||
exceptionWithStackTraceAndMessage("?trace=true&message=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientWithParamsFalse() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-trace-param",
|
||||
"--server.error.include-details=on-details-param");
|
||||
exceptionWithoutStackTraceAndDetails("?trace=false&details=false");
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-param",
|
||||
"--server.error.include-message=on-param");
|
||||
exceptionWithoutStackTraceAndMessage("?trace=false&message=false");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientWithParamsAbsent() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-trace-param",
|
||||
"--server.error.include-details=on-details-param");
|
||||
exceptionWithoutStackTraceAndDetails("");
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=on-param",
|
||||
"--server.error.include-message=on-param");
|
||||
exceptionWithoutStackTraceAndMessage("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientNeverParams() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=never",
|
||||
"--server.error.include-details=never");
|
||||
exceptionWithoutStackTraceAndDetails("?trace=true&details=true");
|
||||
"--server.error.include-message=never");
|
||||
exceptionWithoutStackTraceAndMessage("?trace=true&message=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientAlwaysParams() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-stacktrace=always",
|
||||
"--server.error.include-details=always");
|
||||
exceptionWithStackTraceAndDetails("?trace=false&details=false");
|
||||
"--server.error.include-message=always");
|
||||
exceptionWithStackTraceAndMessage("?trace=false&message=false");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testErrorForMachineClientAlwaysParamsWithoutMessage() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=always");
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=always");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/noMessage"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", IllegalStateException.class,
|
||||
"No message available", "/noMessage");
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void exceptionWithStackTraceAndDetails(String path) {
|
||||
private void exceptionWithStackTraceAndMessage(String path) {
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(path), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", IllegalStateException.class,
|
||||
"Expected!", "/");
|
||||
|
@ -146,26 +152,25 @@ class BasicErrorControllerIntegrationTests {
|
|||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void exceptionWithoutStackTraceAndDetails(String path) {
|
||||
private void exceptionWithoutStackTraceAndMessage(String path) {
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl(path), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", IllegalStateException.class,
|
||||
"An error occurred while processing the request", "/");
|
||||
assertErrorAttributes(entity.getBody(), "500", "Internal Server Error", IllegalStateException.class, "", "/");
|
||||
assertThat(entity.getBody().containsKey("trace")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
void testErrorForAnnotatedExceptionWithoutDetails() {
|
||||
void testErrorForAnnotatedExceptionWithoutMessage() {
|
||||
load("--server.error.include-exception=true");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/annotated"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", TestConfiguration.Errors.ExpectedException.class,
|
||||
"An error occurred while processing the request", "/annotated");
|
||||
"", "/annotated");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
void testErrorForAnnotatedExceptionWithDetails() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=always");
|
||||
void testErrorForAnnotatedExceptionWithMessage() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=always");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/annotated"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", TestConfiguration.Errors.ExpectedException.class,
|
||||
"Expected!", "/annotated");
|
||||
|
@ -173,18 +178,17 @@ class BasicErrorControllerIntegrationTests {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
void testErrorForAnnotatedNoReasonExceptionWithoutDetails() {
|
||||
void testErrorForAnnotatedNoReasonExceptionWithoutMessage() {
|
||||
load("--server.error.include-exception=true");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/annotatedNoReason"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "406", "Not Acceptable",
|
||||
TestConfiguration.Errors.NoReasonExpectedException.class,
|
||||
"An error occurred while processing the request", "/annotatedNoReason");
|
||||
TestConfiguration.Errors.NoReasonExpectedException.class, "", "/annotatedNoReason");
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
void testErrorForAnnotatedNoReasonExceptionWithDetails() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=always");
|
||||
void testErrorForAnnotatedNoReasonExceptionWithMessage() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=always");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/annotatedNoReason"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "406", "Not Acceptable",
|
||||
TestConfiguration.Errors.NoReasonExpectedException.class, "Expected message", "/annotatedNoReason");
|
||||
|
@ -192,8 +196,8 @@ class BasicErrorControllerIntegrationTests {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("rawtypes")
|
||||
void testErrorForAnnotatedNoMessageExceptionWithDetails() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=always");
|
||||
void testErrorForAnnotatedNoMessageExceptionWithMessage() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=always");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/annotatedNoMessage"), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "406", "Not Acceptable",
|
||||
TestConfiguration.Errors.NoReasonExpectedException.class, "No message available",
|
||||
|
@ -201,37 +205,42 @@ class BasicErrorControllerIntegrationTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testBindingExceptionForMachineClientWithDetailsParamTrue() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=on-details-param");
|
||||
bindingExceptionWithDetails("?details=true");
|
||||
void testBindingExceptionForMachineClientWithMessageAndErrorsParamTrue() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=on-param",
|
||||
"--server.error.include-binding-errors=on-param");
|
||||
bindingExceptionWithMessageAndErrors("?message=true&errors=true");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingExceptionForMachineClientWithDetailsParamFalse() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=on-details-param");
|
||||
bindingExceptionWithoutDetails("?details=false");
|
||||
void testBindingExceptionForMachineClientWithMessageAndErrorsParamFalse() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=on-param",
|
||||
"--server.error.include-binding-errors=on-param");
|
||||
bindingExceptionWithoutMessageAndErrors("?message=false&errors=false");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingExceptionForMachineClientWithDetailsParamAbsent() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=on-details-param");
|
||||
bindingExceptionWithoutDetails("");
|
||||
void testBindingExceptionForMachineClientWithMessageAndErrorsParamAbsent() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=on-param",
|
||||
"--server.error.include-binding-errors=on-param");
|
||||
bindingExceptionWithoutMessageAndErrors("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingExceptionForMachineClientAlwaysDetails() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=always");
|
||||
bindingExceptionWithDetails("?details=false");
|
||||
void testBindingExceptionForMachineClientAlwaysMessageAndErrors() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=always",
|
||||
"--server.error.include-binding-errors=always");
|
||||
bindingExceptionWithMessageAndErrors("?message=false&errors=false");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testBindingExceptionForMachineClientNeverDetails() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-details=never");
|
||||
bindingExceptionWithoutDetails("?details=true");
|
||||
void testBindingExceptionForMachineClientNeverMessageAndErrors() {
|
||||
load("--server.error.include-exception=true", "--server.error.include-message=never",
|
||||
"--server.error.include-binding-errors=never");
|
||||
bindingExceptionWithoutMessageAndErrors("?message=true&errors=true");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private void bindingExceptionWithDetails(String param) {
|
||||
private void bindingExceptionWithMessageAndErrors(String param) {
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/bind" + param), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", BindException.class,
|
||||
"Validation failed for object='test'. Error count: 1", "/bind");
|
||||
|
@ -239,10 +248,9 @@ class BasicErrorControllerIntegrationTests {
|
|||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes" })
|
||||
private void bindingExceptionWithoutDetails(String param) {
|
||||
private void bindingExceptionWithoutMessageAndErrors(String param) {
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().getForEntity(createUrl("/bind" + param), Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", BindException.class, "Validation failed",
|
||||
"/bind");
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", BindException.class, "", "/bind");
|
||||
assertThat(entity.getBody().containsKey("errors")).isFalse();
|
||||
}
|
||||
|
||||
|
@ -253,8 +261,8 @@ class BasicErrorControllerIntegrationTests {
|
|||
RequestEntity request = RequestEntity.post(URI.create(createUrl("/bodyValidation")))
|
||||
.accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON).body("{}");
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().exchange(request, Map.class);
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", MethodArgumentNotValidException.class,
|
||||
"Validation failed", "/bodyValidation");
|
||||
assertErrorAttributes(entity.getBody(), "400", "Bad Request", MethodArgumentNotValidException.class, "",
|
||||
"/bodyValidation");
|
||||
assertThat(entity.getBody().containsKey("errors")).isFalse();
|
||||
}
|
||||
|
||||
|
@ -262,7 +270,7 @@ class BasicErrorControllerIntegrationTests {
|
|||
@SuppressWarnings("rawtypes")
|
||||
void testBindingExceptionForMachineClientDefault() {
|
||||
load();
|
||||
RequestEntity request = RequestEntity.get(URI.create(createUrl("/bind?trace=true,details=true")))
|
||||
RequestEntity request = RequestEntity.get(URI.create(createUrl("/bind?trace=true,message=true")))
|
||||
.accept(MediaType.APPLICATION_JSON).build();
|
||||
ResponseEntity<Map> entity = new TestRestTemplate().exchange(request, Map.class);
|
||||
assertThat(entity.getBody().containsKey("exception")).isFalse();
|
||||
|
|
|
@ -69,7 +69,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(properties = { "server.error.include-details=always" })
|
||||
@SpringBootTest(properties = { "server.error.include-message=always" })
|
||||
@DirtiesContext
|
||||
class BasicErrorControllerMockMvcTests {
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
|
|||
* @author Dave Syer
|
||||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(properties = { "server.error.include-details=always" })
|
||||
@SpringBootTest(properties = { "server.error.include-message=always" })
|
||||
@DirtiesContext
|
||||
class DefaultErrorViewIntegrationTests {
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ class ErrorMvcAutoConfigurationTests {
|
|||
ErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);
|
||||
DispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException("Exception message"),
|
||||
false);
|
||||
errorView.render(errorAttributes.getErrorAttributes(webRequest, true, true), webRequest.getRequest(),
|
||||
errorView.render(errorAttributes.getErrorAttributes(webRequest, true, true, true), webRequest.getRequest(),
|
||||
webRequest.getResponse());
|
||||
assertThat(webRequest.getResponse().getContentType()).isEqualTo("text/html;charset=UTF-8");
|
||||
String responseString = ((MockHttpServletResponse) webRequest.getResponse()).getContentAsString();
|
||||
|
@ -69,7 +69,7 @@ class ErrorMvcAutoConfigurationTests {
|
|||
ErrorAttributes errorAttributes = context.getBean(ErrorAttributes.class);
|
||||
DispatcherServletWebRequest webRequest = createWebRequest(new IllegalStateException("Exception message"),
|
||||
true);
|
||||
errorView.render(errorAttributes.getErrorAttributes(webRequest, true, true), webRequest.getRequest(),
|
||||
errorView.render(errorAttributes.getErrorAttributes(webRequest, true, true, true), webRequest.getRequest(),
|
||||
webRequest.getResponse());
|
||||
assertThat(output).contains("Cannot render error page for request [/path] "
|
||||
+ "and exception [Exception message] as the response has "
|
||||
|
|
|
@ -71,7 +71,8 @@ public class DevToolsPropertyDefaultsPostProcessor implements EnvironmentPostPro
|
|||
properties.put("spring.resources.chain.cache", "false");
|
||||
properties.put("spring.template.provider.cache", "false");
|
||||
properties.put("spring.mvc.log-resolved-exception", "true");
|
||||
properties.put("server.error.include-details", "ALWAYS");
|
||||
properties.put("server.error.include-binding-errors", "ALWAYS");
|
||||
properties.put("server.error.include-message", "ALWAYS");
|
||||
properties.put("server.error.include-stacktrace", "ALWAYS");
|
||||
properties.put("server.servlet.jsp.init-parameters.development", "true");
|
||||
properties.put("spring.reactor.debug", "true");
|
||||
|
|
|
@ -108,8 +108,8 @@ class DevToolPropertiesIntegrationTests {
|
|||
ConfigurableEnvironment environment = this.context.getEnvironment();
|
||||
String includeStackTrace = environment.getProperty("server.error.include-stacktrace");
|
||||
assertThat(includeStackTrace).isEqualTo(ErrorProperties.IncludeStacktrace.ALWAYS.toString());
|
||||
String includeDetails = environment.getProperty("server.error.include-details");
|
||||
assertThat(includeDetails).isEqualTo(ErrorProperties.IncludeDetails.ALWAYS.toString());
|
||||
String includeMessage = environment.getProperty("server.error.include-message");
|
||||
assertThat(includeMessage).isEqualTo(ErrorProperties.IncludeAttribute.ALWAYS.toString());
|
||||
}
|
||||
|
||||
protected ConfigurableApplicationContext getContext(Supplier<ConfigurableApplicationContext> supplier)
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.springframework.util.StringUtils;
|
|||
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;
|
||||
import org.springframework.web.server.ServerWebExchange;
|
||||
|
@ -82,12 +81,12 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
|||
@Override
|
||||
@Deprecated
|
||||
public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
|
||||
return getErrorAttributes(request, includeStackTrace, false);
|
||||
return getErrorAttributes(request, includeStackTrace, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace,
|
||||
boolean includeDetails) {
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
Map<String, Object> errorAttributes = new LinkedHashMap<>();
|
||||
errorAttributes.put("timestamp", new Date());
|
||||
errorAttributes.put("path", request.path());
|
||||
|
@ -97,9 +96,9 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
|||
HttpStatus errorStatus = determineHttpStatus(error, responseStatusAnnotation);
|
||||
errorAttributes.put("status", errorStatus.value());
|
||||
errorAttributes.put("error", errorStatus.getReasonPhrase());
|
||||
errorAttributes.put("message", determineMessage(error, responseStatusAnnotation, includeDetails));
|
||||
errorAttributes.put("message", determineMessage(error, responseStatusAnnotation, includeMessage));
|
||||
errorAttributes.put("requestId", request.exchange().getRequest().getId());
|
||||
handleException(errorAttributes, determineException(error), includeStackTrace, includeDetails);
|
||||
handleException(errorAttributes, determineException(error), includeStackTrace, includeBindingErrors);
|
||||
return errorAttributes;
|
||||
}
|
||||
|
||||
|
@ -111,13 +110,13 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
|||
}
|
||||
|
||||
private String determineMessage(Throwable error, MergedAnnotation<ResponseStatus> responseStatusAnnotation,
|
||||
boolean includeDetails) {
|
||||
if (error instanceof WebExchangeBindException) {
|
||||
return includeDetails ? error.getMessage() : "Validation failed";
|
||||
}
|
||||
if (!includeDetails) {
|
||||
boolean includeMessage) {
|
||||
if (!includeMessage) {
|
||||
return "";
|
||||
}
|
||||
if (error instanceof BindingResult) {
|
||||
return error.getMessage();
|
||||
}
|
||||
if (error instanceof ResponseStatusException) {
|
||||
return ((ResponseStatusException) error).getReason();
|
||||
}
|
||||
|
@ -143,14 +142,14 @@ public class DefaultErrorAttributes implements ErrorAttributes {
|
|||
}
|
||||
|
||||
private void handleException(Map<String, Object> errorAttributes, Throwable error, boolean includeStackTrace,
|
||||
boolean includeDetails) {
|
||||
boolean includeBindingErrors) {
|
||||
if (this.includeException) {
|
||||
errorAttributes.put("exception", error.getClass().getName());
|
||||
}
|
||||
if (includeStackTrace) {
|
||||
addStackTrace(errorAttributes, error);
|
||||
}
|
||||
if (includeDetails && (error instanceof BindingResult)) {
|
||||
if (includeBindingErrors && (error instanceof BindingResult)) {
|
||||
BindingResult result = (BindingResult) error;
|
||||
if (result.hasErrors()) {
|
||||
errorAttributes.put("errors", result.getAllErrors());
|
||||
|
|
|
@ -36,10 +36,10 @@ public interface ErrorAttributes {
|
|||
* Return a {@link Map} of the error attributes. The map can be used as the model of
|
||||
* an error page, or returned as a {@link ServerResponse} body.
|
||||
* @param request the source request
|
||||
* @param includeStackTrace if stack trace elements should be included
|
||||
* @param includeStackTrace if stack trace attribute should be included
|
||||
* @return a map of error attributes
|
||||
* @deprecated since 2.3.0 in favor of
|
||||
* {@link #getErrorAttributes(ServerRequest, boolean, boolean)}
|
||||
* {@link #getErrorAttributes(ServerRequest, boolean, boolean, boolean)}
|
||||
*/
|
||||
Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace);
|
||||
|
||||
|
@ -47,11 +47,13 @@ public interface ErrorAttributes {
|
|||
* Return a {@link Map} of the error attributes. The map can be used as the model of
|
||||
* an error page, or returned as a {@link ServerResponse} body.
|
||||
* @param request the source request
|
||||
* @param includeStackTrace if stack trace elements should be included
|
||||
* @param includeDetails if message and errors elements should be included
|
||||
* @param includeStackTrace if stack trace attribute should be included
|
||||
* @param includeMessage if message attribute should be included
|
||||
* @param includeBindingErrors if errors attribute should be included
|
||||
* @return a map of error attributes
|
||||
*/
|
||||
Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace, boolean includeDetails);
|
||||
Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace, boolean includeMessage,
|
||||
boolean includeBindingErrors);
|
||||
|
||||
/**
|
||||
* Return the underlying cause of the error or {@code null} if the error cannot be
|
||||
|
|
|
@ -104,16 +104,16 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
|||
@Override
|
||||
@Deprecated
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace) {
|
||||
return getErrorAttributes(webRequest, includeStackTrace, false);
|
||||
return getErrorAttributes(webRequest, includeStackTrace, false, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace,
|
||||
boolean includeDetails) {
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
Map<String, Object> errorAttributes = new LinkedHashMap<>();
|
||||
errorAttributes.put("timestamp", new Date());
|
||||
addStatus(errorAttributes, webRequest);
|
||||
addErrorDetails(errorAttributes, webRequest, includeStackTrace, includeDetails);
|
||||
addErrorDetails(errorAttributes, webRequest, includeStackTrace, includeMessage, includeBindingErrors);
|
||||
addPath(errorAttributes, webRequest);
|
||||
return errorAttributes;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
|||
}
|
||||
|
||||
private void addErrorDetails(Map<String, Object> errorAttributes, WebRequest webRequest, boolean includeStackTrace,
|
||||
boolean includeDetails) {
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
Throwable error = getError(webRequest);
|
||||
if (error != null) {
|
||||
while (error instanceof ServletException && error.getCause() != null) {
|
||||
|
@ -149,24 +149,24 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
|||
addStackTrace(errorAttributes, error);
|
||||
}
|
||||
}
|
||||
addErrorMessage(errorAttributes, webRequest, error, includeDetails);
|
||||
addErrorMessage(errorAttributes, webRequest, error, includeMessage, includeBindingErrors);
|
||||
}
|
||||
|
||||
private void addErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error,
|
||||
boolean includeDetails) {
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
BindingResult result = extractBindingResult(error);
|
||||
if (result == null) {
|
||||
addExceptionErrorMessage(errorAttributes, webRequest, error, includeDetails);
|
||||
addExceptionErrorMessage(errorAttributes, webRequest, error, includeMessage);
|
||||
}
|
||||
else {
|
||||
addBindingResultErrorMessage(errorAttributes, result, includeDetails);
|
||||
addBindingResultErrorMessage(errorAttributes, result, includeMessage, includeBindingErrors);
|
||||
}
|
||||
}
|
||||
|
||||
private void addExceptionErrorMessage(Map<String, Object> errorAttributes, WebRequest webRequest, Throwable error,
|
||||
boolean includeDetails) {
|
||||
if (!includeDetails) {
|
||||
errorAttributes.put("message", "An error occurred while processing the request");
|
||||
boolean includeMessage) {
|
||||
if (!includeMessage) {
|
||||
errorAttributes.put("message", "");
|
||||
return;
|
||||
}
|
||||
Object message = getAttribute(webRequest, RequestDispatcher.ERROR_MESSAGE);
|
||||
|
@ -180,16 +180,12 @@ public class DefaultErrorAttributes implements ErrorAttributes, HandlerException
|
|||
}
|
||||
|
||||
private void addBindingResultErrorMessage(Map<String, Object> errorAttributes, BindingResult result,
|
||||
boolean includeDetails) {
|
||||
if (!includeDetails) {
|
||||
errorAttributes.put("message", "Validation failed");
|
||||
return;
|
||||
}
|
||||
if (result.hasErrors()) {
|
||||
boolean includeMessage, boolean includeBindingErrors) {
|
||||
errorAttributes.put("message", (includeMessage) ? "Validation failed for object='" + result.getObjectName()
|
||||
+ "'. " + "Error count: " + result.getErrorCount() : "");
|
||||
if (includeBindingErrors && result.hasErrors()) {
|
||||
errorAttributes.put("errors", result.getAllErrors());
|
||||
}
|
||||
errorAttributes.put("message", "Validation failed for object='" + result.getObjectName() + "'. "
|
||||
+ "Error count: " + result.getErrorCount());
|
||||
}
|
||||
|
||||
private BindingResult extractBindingResult(Throwable error) {
|
||||
|
|
|
@ -37,10 +37,10 @@ public interface ErrorAttributes {
|
|||
* an error page {@link ModelAndView}, or returned as a
|
||||
* {@link ResponseBody @ResponseBody}.
|
||||
* @param webRequest the source request
|
||||
* @param includeStackTrace if stack trace elements should be included
|
||||
* @param includeStackTrace if stack trace element should be included
|
||||
* @return a map of error attributes
|
||||
* @deprecated since 2.3.0 in favor of
|
||||
* {@link #getErrorAttributes(WebRequest, boolean, boolean)}
|
||||
* {@link #getErrorAttributes(WebRequest, boolean, boolean, boolean)}
|
||||
*/
|
||||
@Deprecated
|
||||
Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace);
|
||||
|
@ -50,12 +50,14 @@ public interface ErrorAttributes {
|
|||
* an error page {@link ModelAndView}, or returned as a
|
||||
* {@link ResponseBody @ResponseBody}.
|
||||
* @param webRequest the source request
|
||||
* @param includeStackTrace if stack trace elements should be included
|
||||
* @param includeDetails if message and errors elements should be included
|
||||
* @param includeStackTrace if stack trace element should be included
|
||||
* @param includeMessage if message element should be included
|
||||
* @param includeBindingErrors if errors element should be included
|
||||
* @return a map of error attributes
|
||||
* @since 2.3.0
|
||||
*/
|
||||
Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace, boolean includeDetails);
|
||||
Map<String, Object> getErrorAttributes(WebRequest webRequest, boolean includeStackTrace, boolean includeMessage,
|
||||
boolean includeBindingErrors);
|
||||
|
||||
/**
|
||||
* Return the underlying cause of the error or {@code null} if the error cannot be
|
||||
|
|
|
@ -62,7 +62,7 @@ class DefaultErrorAttributesTests {
|
|||
MockServerWebExchange exchange = MockServerWebExchange.from(MockServerHttpRequest.get("/test").build());
|
||||
ServerRequest request = ServerRequest.create(exchange, this.readers);
|
||||
assertThatIllegalStateException()
|
||||
.isThrownBy(() -> this.errorAttributes.getErrorAttributes(request, false, false))
|
||||
.isThrownBy(() -> this.errorAttributes.getErrorAttributes(request, false, false, false))
|
||||
.withMessageContaining("Missing exception attribute in ServerWebExchange");
|
||||
}
|
||||
|
||||
|
@ -70,7 +70,7 @@ class DefaultErrorAttributesTests {
|
|||
void includeTimeStamp() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, NOT_FOUND),
|
||||
false, false);
|
||||
false, false, false);
|
||||
assertThat(attributes.get("timestamp")).isInstanceOf(Date.class);
|
||||
}
|
||||
|
||||
|
@ -79,7 +79,7 @@ class DefaultErrorAttributesTests {
|
|||
Error error = new OutOfMemoryError("Test error");
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error),
|
||||
false, false);
|
||||
false, false, false);
|
||||
assertThat(attributes.get("error")).isEqualTo(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase());
|
||||
assertThat(attributes.get("status")).isEqualTo(500);
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ class DefaultErrorAttributesTests {
|
|||
Exception error = new CustomException();
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error),
|
||||
false, false);
|
||||
false, false, 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());
|
||||
|
@ -100,7 +100,7 @@ class DefaultErrorAttributesTests {
|
|||
Exception error = new CustomException("Test Message");
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error),
|
||||
false, true);
|
||||
false, true, 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());
|
||||
|
@ -111,7 +111,7 @@ class DefaultErrorAttributesTests {
|
|||
Exception error = new Custom2Exception();
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, error),
|
||||
false, true);
|
||||
false, true, 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!");
|
||||
|
@ -121,7 +121,7 @@ class DefaultErrorAttributesTests {
|
|||
void includeStatusCode() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, NOT_FOUND),
|
||||
false, false);
|
||||
false, false, false);
|
||||
assertThat(attributes.get("error")).isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase());
|
||||
assertThat(attributes.get("status")).isEqualTo(404);
|
||||
}
|
||||
|
@ -131,18 +131,18 @@ class DefaultErrorAttributesTests {
|
|||
Error error = new OutOfMemoryError("Test error");
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
ServerRequest serverRequest = buildServerRequest(request, error);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true, false);
|
||||
assertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);
|
||||
assertThat(attributes.get("exception")).isNull();
|
||||
assertThat(attributes.get("message")).isEqualTo("Test error");
|
||||
}
|
||||
|
||||
@Test
|
||||
void excludeDetails() {
|
||||
void excludeMessage() {
|
||||
Error error = new OutOfMemoryError("Test error");
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
ServerRequest serverRequest = buildServerRequest(request, error);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, false, false);
|
||||
assertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);
|
||||
assertThat(attributes.get("message")).isEqualTo("");
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ class DefaultErrorAttributesTests {
|
|||
this.errorAttributes = new DefaultErrorAttributes(true);
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
ServerRequest serverRequest = buildServerRequest(request, error);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true, false);
|
||||
assertThat(this.errorAttributes.getError(serverRequest)).isSameAs(error);
|
||||
assertThat(attributes.get("exception")).isEqualTo(RuntimeException.class.getName());
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
|
@ -166,7 +166,7 @@ class DefaultErrorAttributesTests {
|
|||
this.errorAttributes = new DefaultErrorAttributes(true);
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
ServerRequest serverRequest = buildServerRequest(request, error);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true, false);
|
||||
assertThat(attributes.get("status")).isEqualTo(400);
|
||||
assertThat(attributes.get("message")).isEqualTo("invalid request");
|
||||
assertThat(attributes.get("exception")).isEqualTo(RuntimeException.class.getName());
|
||||
|
@ -180,7 +180,7 @@ class DefaultErrorAttributesTests {
|
|||
this.errorAttributes = new DefaultErrorAttributes(true);
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
ServerRequest serverRequest = buildServerRequest(request, error);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, true, false);
|
||||
assertThat(attributes.get("status")).isEqualTo(406);
|
||||
assertThat(attributes.get("message")).isEqualTo("could not process request");
|
||||
assertThat(attributes.get("exception")).isEqualTo(ResponseStatusException.class.getName());
|
||||
|
@ -192,7 +192,7 @@ class DefaultErrorAttributesTests {
|
|||
RuntimeException ex = new RuntimeException("Test");
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, ex), false,
|
||||
false);
|
||||
false, false);
|
||||
assertThat(attributes.get("trace")).isNull();
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ class DefaultErrorAttributesTests {
|
|||
RuntimeException ex = new RuntimeException("Test");
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, ex), true,
|
||||
false);
|
||||
false, false);
|
||||
assertThat(attributes.get("trace").toString()).startsWith("java.lang");
|
||||
}
|
||||
|
||||
|
@ -209,7 +209,7 @@ class DefaultErrorAttributesTests {
|
|||
void includePath() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, NOT_FOUND),
|
||||
false, false);
|
||||
false, false, false);
|
||||
assertThat(attributes.get("path")).isEqualTo("/test");
|
||||
}
|
||||
|
||||
|
@ -217,7 +217,7 @@ class DefaultErrorAttributesTests {
|
|||
void includeLogPrefix() {
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
ServerRequest serverRequest = buildServerRequest(request, NOT_FOUND);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(serverRequest, false, false, false);
|
||||
assertThat(attributes.get("requestId")).isEqualTo(serverRequest.exchange().getRequest().getId());
|
||||
}
|
||||
|
||||
|
@ -230,7 +230,7 @@ class DefaultErrorAttributesTests {
|
|||
Exception ex = new WebExchangeBindException(stringParam, bindingResult);
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, ex), false,
|
||||
true);
|
||||
true, true);
|
||||
assertThat(attributes.get("message")).asString()
|
||||
.startsWith("Validation failed for argument at index 0 in method: "
|
||||
+ "int org.springframework.boot.web.reactive.error.DefaultErrorAttributesTests"
|
||||
|
@ -239,7 +239,7 @@ class DefaultErrorAttributesTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void extractBindingResultErrorsExcludeDetails() throws Exception {
|
||||
void extractBindingResultErrorsExcludeMessageAndErrors() throws Exception {
|
||||
Method method = getClass().getDeclaredMethod("method", String.class);
|
||||
MethodParameter stringParam = new MethodParameter(method, 0);
|
||||
BindingResult bindingResult = new MapBindingResult(Collections.singletonMap("a", "b"), "objectName");
|
||||
|
@ -247,8 +247,8 @@ class DefaultErrorAttributesTests {
|
|||
Exception ex = new WebExchangeBindException(stringParam, bindingResult);
|
||||
MockServerHttpRequest request = MockServerHttpRequest.get("/test").build();
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(buildServerRequest(request, ex), false,
|
||||
false);
|
||||
assertThat(attributes.get("message")).isEqualTo("Validation failed");
|
||||
false, false);
|
||||
assertThat(attributes.get("message")).isEqualTo("");
|
||||
assertThat(attributes.containsKey("errors")).isFalse();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,21 +54,21 @@ class DefaultErrorAttributesTests {
|
|||
|
||||
@Test
|
||||
void includeTimeStamp() {
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(attributes.get("timestamp")).isInstanceOf(Date.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void specificStatusCode() {
|
||||
this.request.setAttribute("javax.servlet.error.status_code", 404);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(attributes.get("error")).isEqualTo(HttpStatus.NOT_FOUND.getReasonPhrase());
|
||||
assertThat(attributes.get("status")).isEqualTo(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
void missingStatusCode() {
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(attributes.get("error")).isEqualTo("None");
|
||||
assertThat(attributes.get("status")).isEqualTo(999);
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ class DefaultErrorAttributesTests {
|
|||
RuntimeException ex = new RuntimeException("Test");
|
||||
ModelAndView modelAndView = this.errorAttributes.resolveException(this.request, null, null, ex);
|
||||
this.request.setAttribute("javax.servlet.error.exception", new RuntimeException("Ignored"));
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(ex);
|
||||
assertThat(modelAndView).isNull();
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
|
@ -86,46 +86,46 @@ class DefaultErrorAttributesTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void servletErrorWithDetail() {
|
||||
void servletErrorWithMessage() {
|
||||
RuntimeException ex = new RuntimeException("Test");
|
||||
this.request.setAttribute("javax.servlet.error.exception", ex);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(ex);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletErrorWithoutDetail() {
|
||||
void servletErrorWithoutMessage() {
|
||||
RuntimeException ex = new RuntimeException("Test");
|
||||
this.request.setAttribute("javax.servlet.error.exception", ex);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(ex);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message").toString()).contains("An error occurred");
|
||||
assertThat(attributes.get("message").toString()).contains("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMessageWithDetail() {
|
||||
void servletMessageWithMessage() {
|
||||
this.request.setAttribute("javax.servlet.error.message", "Test");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
}
|
||||
|
||||
@Test
|
||||
void servletMessageWithoutDetail() {
|
||||
void servletMessageWithoutMessage() {
|
||||
this.request.setAttribute("javax.servlet.error.message", "Test");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).asString().contains("An error occurred");
|
||||
assertThat(attributes.get("message")).asString().contains("");
|
||||
}
|
||||
|
||||
@Test
|
||||
void nullExceptionMessage() {
|
||||
this.request.setAttribute("javax.servlet.error.exception", new RuntimeException());
|
||||
this.request.setAttribute("javax.servlet.error.message", "Test");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ class DefaultErrorAttributesTests {
|
|||
@Test
|
||||
void nullExceptionMessageAndServletMessage() {
|
||||
this.request.setAttribute("javax.servlet.error.exception", new RuntimeException());
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).isEqualTo("No message available");
|
||||
}
|
||||
|
@ -143,7 +143,7 @@ class DefaultErrorAttributesTests {
|
|||
RuntimeException ex = new RuntimeException("Test");
|
||||
ServletException wrapped = new ServletException(new ServletException(ex));
|
||||
this.request.setAttribute("javax.servlet.error.exception", wrapped);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(wrapped);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
|
@ -153,7 +153,7 @@ class DefaultErrorAttributesTests {
|
|||
void getError() {
|
||||
Error error = new OutOfMemoryError("Test error");
|
||||
this.request.setAttribute("javax.servlet.error.exception", error);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(this.errorAttributes.getError(this.webRequest)).isSameAs(error);
|
||||
assertThat(attributes.containsKey("exception")).isFalse();
|
||||
assertThat(attributes.get("message")).isEqualTo("Test error");
|
||||
|
@ -183,17 +183,17 @@ class DefaultErrorAttributesTests {
|
|||
testBindingResult(bindingResult, ex, true);
|
||||
}
|
||||
|
||||
private void testBindingResult(BindingResult bindingResult, Exception ex, boolean includeDetails) {
|
||||
private void testBindingResult(BindingResult bindingResult, Exception ex, boolean includeMessageAndErrors) {
|
||||
this.request.setAttribute("javax.servlet.error.exception", ex);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false,
|
||||
includeDetails);
|
||||
if (includeDetails) {
|
||||
includeMessageAndErrors, includeMessageAndErrors);
|
||||
if (includeMessageAndErrors) {
|
||||
assertThat(attributes.get("message"))
|
||||
.isEqualTo("Validation failed for object='objectName'. Error count: 1");
|
||||
assertThat(attributes.get("errors")).isEqualTo(bindingResult.getAllErrors());
|
||||
}
|
||||
else {
|
||||
assertThat(attributes.get("message")).isEqualTo("Validation failed");
|
||||
assertThat(attributes.get("message")).isEqualTo("");
|
||||
assertThat(attributes.containsKey("errors")).isFalse();
|
||||
}
|
||||
}
|
||||
|
@ -203,7 +203,7 @@ class DefaultErrorAttributesTests {
|
|||
DefaultErrorAttributes errorAttributes = new DefaultErrorAttributes(true);
|
||||
RuntimeException ex = new RuntimeException("Test");
|
||||
this.request.setAttribute("javax.servlet.error.exception", ex);
|
||||
Map<String, Object> attributes = errorAttributes.getErrorAttributes(this.webRequest, false, true);
|
||||
Map<String, Object> attributes = errorAttributes.getErrorAttributes(this.webRequest, false, true, false);
|
||||
assertThat(attributes.get("exception")).isEqualTo(RuntimeException.class.getName());
|
||||
assertThat(attributes.get("message")).isEqualTo("Test");
|
||||
}
|
||||
|
@ -212,7 +212,7 @@ class DefaultErrorAttributesTests {
|
|||
void withStackTraceAttribute() {
|
||||
RuntimeException ex = new RuntimeException("Test");
|
||||
this.request.setAttribute("javax.servlet.error.exception", ex);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, true, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, true, false, false);
|
||||
assertThat(attributes.get("trace").toString()).startsWith("java.lang");
|
||||
}
|
||||
|
||||
|
@ -220,14 +220,14 @@ class DefaultErrorAttributesTests {
|
|||
void withoutStackTraceAttribute() {
|
||||
RuntimeException ex = new RuntimeException("Test");
|
||||
this.request.setAttribute("javax.servlet.error.exception", ex);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(attributes.containsKey("trace")).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void path() {
|
||||
this.request.setAttribute("javax.servlet.error.request_uri", "path");
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false);
|
||||
Map<String, Object> attributes = this.errorAttributes.getErrorAttributes(this.webRequest, false, false, false);
|
||||
assertThat(attributes.get("path")).isEqualTo("path");
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
* @author Scott Frederick
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
|
||||
properties = { "server.error.include-details=always" })
|
||||
properties = { "server.error.include-message=always" })
|
||||
class SampleActuatorCustomSecurityApplicationTests extends AbstractSampleActuatorCustomSecurityTests {
|
||||
|
||||
@LocalServerPort
|
||||
|
|
|
@ -39,7 +39,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "server.error.include-details=always" })
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT, properties = { "server.error.include-message=always" })
|
||||
class SampleActuatorUiApplicationTests {
|
||||
|
||||
@Autowired
|
||||
|
|
Loading…
Reference in New Issue