|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2012-2023 the original author or authors. |
|
|
|
* Copyright 2012-2024 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -20,6 +20,7 @@ import java.io.PrintWriter; |
|
|
|
import java.io.StringWriter; |
|
|
|
import java.io.StringWriter; |
|
|
|
import java.util.Date; |
|
|
|
import java.util.Date; |
|
|
|
import java.util.LinkedHashMap; |
|
|
|
import java.util.LinkedHashMap; |
|
|
|
|
|
|
|
import java.util.List; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Map; |
|
|
|
import java.util.Optional; |
|
|
|
import java.util.Optional; |
|
|
|
|
|
|
|
|
|
|
|
@ -32,6 +33,7 @@ import org.springframework.http.HttpStatus; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
import org.springframework.validation.BindingResult; |
|
|
|
import org.springframework.validation.BindingResult; |
|
|
|
import org.springframework.validation.ObjectError; |
|
|
|
import org.springframework.validation.ObjectError; |
|
|
|
|
|
|
|
import org.springframework.validation.method.MethodValidationResult; |
|
|
|
import org.springframework.web.bind.annotation.ResponseStatus; |
|
|
|
import org.springframework.web.bind.annotation.ResponseStatus; |
|
|
|
import org.springframework.web.reactive.function.server.ServerRequest; |
|
|
|
import org.springframework.web.reactive.function.server.ServerRequest; |
|
|
|
import org.springframework.web.server.ResponseStatusException; |
|
|
|
import org.springframework.web.server.ResponseStatusException; |
|
|
|
@ -46,8 +48,8 @@ import org.springframework.web.server.ServerWebExchange; |
|
|
|
* <li>error - The error reason</li> |
|
|
|
* <li>error - The error reason</li> |
|
|
|
* <li>exception - The class name of the root exception (if configured)</li> |
|
|
|
* <li>exception - The class name of the root exception (if configured)</li> |
|
|
|
* <li>message - The exception message (if configured)</li> |
|
|
|
* <li>message - The exception message (if configured)</li> |
|
|
|
* <li>errors - Any {@link ObjectError}s from a {@link BindingResult} exception (if |
|
|
|
* <li>errors - Any {@link ObjectError}s from a {@link BindingResult} or |
|
|
|
* configured)</li> |
|
|
|
* {@link MethodValidationResult} exception (if configured)</li> |
|
|
|
* <li>trace - The exception stack trace (if configured)</li> |
|
|
|
* <li>trace - The exception stack trace (if configured)</li> |
|
|
|
* <li>path - The URL path when the exception was raised</li> |
|
|
|
* <li>path - The URL path when the exception was raised</li> |
|
|
|
* <li>requestId - Unique ID associated with the current request</li> |
|
|
|
* <li>requestId - Unique ID associated with the current request</li> |
|
|
|
@ -57,6 +59,7 @@ import org.springframework.web.server.ServerWebExchange; |
|
|
|
* @author Stephane Nicoll |
|
|
|
* @author Stephane Nicoll |
|
|
|
* @author Michele Mancioppi |
|
|
|
* @author Michele Mancioppi |
|
|
|
* @author Scott Frederick |
|
|
|
* @author Scott Frederick |
|
|
|
|
|
|
|
* @author Yanming Zhou |
|
|
|
* @since 2.0.0 |
|
|
|
* @since 2.0.0 |
|
|
|
* @see ErrorAttributes |
|
|
|
* @see ErrorAttributes |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
@ -93,9 +96,8 @@ public class DefaultErrorAttributes implements ErrorAttributes { |
|
|
|
HttpStatus errorStatus = determineHttpStatus(error, responseStatusAnnotation); |
|
|
|
HttpStatus errorStatus = determineHttpStatus(error, responseStatusAnnotation); |
|
|
|
errorAttributes.put("status", errorStatus.value()); |
|
|
|
errorAttributes.put("status", errorStatus.value()); |
|
|
|
errorAttributes.put("error", errorStatus.getReasonPhrase()); |
|
|
|
errorAttributes.put("error", errorStatus.getReasonPhrase()); |
|
|
|
errorAttributes.put("message", determineMessage(error, responseStatusAnnotation)); |
|
|
|
|
|
|
|
errorAttributes.put("requestId", request.exchange().getRequest().getId()); |
|
|
|
errorAttributes.put("requestId", request.exchange().getRequest().getId()); |
|
|
|
handleException(errorAttributes, determineException(error), includeStackTrace); |
|
|
|
handleException(errorAttributes, error, responseStatusAnnotation, includeStackTrace); |
|
|
|
return errorAttributes; |
|
|
|
return errorAttributes; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -109,27 +111,6 @@ public class DefaultErrorAttributes implements ErrorAttributes { |
|
|
|
return responseStatusAnnotation.getValue("code", HttpStatus.class).orElse(HttpStatus.INTERNAL_SERVER_ERROR); |
|
|
|
return responseStatusAnnotation.getValue("code", HttpStatus.class).orElse(HttpStatus.INTERNAL_SERVER_ERROR); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private String determineMessage(Throwable error, MergedAnnotation<ResponseStatus> responseStatusAnnotation) { |
|
|
|
|
|
|
|
if (error instanceof BindingResult) { |
|
|
|
|
|
|
|
return error.getMessage(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (error instanceof ResponseStatusException responseStatusException) { |
|
|
|
|
|
|
|
return responseStatusException.getReason(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
String reason = responseStatusAnnotation.getValue("reason", String.class).orElse(""); |
|
|
|
|
|
|
|
if (StringUtils.hasText(reason)) { |
|
|
|
|
|
|
|
return reason; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return (error.getMessage() != null) ? error.getMessage() : ""; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private Throwable determineException(Throwable error) { |
|
|
|
|
|
|
|
if (error instanceof ResponseStatusException) { |
|
|
|
|
|
|
|
return (error.getCause() != null) ? error.getCause() : error; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return error; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void addStackTrace(Map<String, Object> errorAttributes, Throwable error) { |
|
|
|
private void addStackTrace(Map<String, Object> errorAttributes, Throwable error) { |
|
|
|
StringWriter stackTrace = new StringWriter(); |
|
|
|
StringWriter stackTrace = new StringWriter(); |
|
|
|
error.printStackTrace(new PrintWriter(stackTrace)); |
|
|
|
error.printStackTrace(new PrintWriter(stackTrace)); |
|
|
|
@ -137,16 +118,44 @@ public class DefaultErrorAttributes implements ErrorAttributes { |
|
|
|
errorAttributes.put("trace", stackTrace.toString()); |
|
|
|
errorAttributes.put("trace", stackTrace.toString()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private void handleException(Map<String, Object> errorAttributes, Throwable error, boolean includeStackTrace) { |
|
|
|
private void handleException(Map<String, Object> errorAttributes, Throwable error, |
|
|
|
errorAttributes.put("exception", error.getClass().getName()); |
|
|
|
MergedAnnotation<ResponseStatus> responseStatusAnnotation, boolean includeStackTrace) { |
|
|
|
if (includeStackTrace) { |
|
|
|
Throwable exception; |
|
|
|
addStackTrace(errorAttributes, error); |
|
|
|
if (error instanceof BindingResult bindingResult) { |
|
|
|
|
|
|
|
errorAttributes.put("message", error.getMessage()); |
|
|
|
|
|
|
|
errorAttributes.put("errors", bindingResult.getAllErrors()); |
|
|
|
|
|
|
|
exception = error; |
|
|
|
} |
|
|
|
} |
|
|
|
if (error instanceof BindingResult result) { |
|
|
|
else if (error instanceof MethodValidationResult methodValidationResult) { |
|
|
|
if (result.hasErrors()) { |
|
|
|
addMessageAndErrorsFromMethodValidationResult(errorAttributes, methodValidationResult); |
|
|
|
errorAttributes.put("errors", result.getAllErrors()); |
|
|
|
exception = error; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
else if (error instanceof ResponseStatusException responseStatusException) { |
|
|
|
|
|
|
|
errorAttributes.put("message", responseStatusException.getReason()); |
|
|
|
|
|
|
|
exception = (responseStatusException.getCause() != null) ? responseStatusException.getCause() : error; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
exception = error; |
|
|
|
|
|
|
|
String reason = responseStatusAnnotation.getValue("reason", String.class).orElse(""); |
|
|
|
|
|
|
|
String message = StringUtils.hasText(reason) ? reason : error.getMessage(); |
|
|
|
|
|
|
|
errorAttributes.put("message", (message != null) ? message : ""); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
errorAttributes.put("exception", exception.getClass().getName()); |
|
|
|
|
|
|
|
if (includeStackTrace) { |
|
|
|
|
|
|
|
addStackTrace(errorAttributes, exception); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void addMessageAndErrorsFromMethodValidationResult(Map<String, Object> errorAttributes, |
|
|
|
|
|
|
|
MethodValidationResult result) { |
|
|
|
|
|
|
|
List<ObjectError> errors = result.getAllErrors() |
|
|
|
|
|
|
|
.stream() |
|
|
|
|
|
|
|
.filter(ObjectError.class::isInstance) |
|
|
|
|
|
|
|
.map(ObjectError.class::cast) |
|
|
|
|
|
|
|
.toList(); |
|
|
|
|
|
|
|
errorAttributes.put("message", |
|
|
|
|
|
|
|
"Validation failed for method='" + result.getMethod() + "'. Error count: " + errors.size()); |
|
|
|
|
|
|
|
errorAttributes.put("errors", errors); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
|