Improve mapping any Exception to ErrorResponse
Add protected, convenience method in ResponseEntityExceptionHandler to create a ProblemDetail for any exception, along with a MessageSource lookup for the "detail" field. Closes gh-29384
This commit is contained in:
@@ -292,6 +292,35 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
|
||||
return handleExceptionInternal(ex, null, headers, status, exchange);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to create a {@link ProblemDetail} for any exception
|
||||
* that doesn't implement {@link ErrorResponse}, also performing a
|
||||
* {@link MessageSource} lookup for the "detail" field.
|
||||
* @param ex the exception being handled
|
||||
* @param status the status to associate with the exception
|
||||
* @param defaultDetail default value for the "detail" field
|
||||
* @param detailMessageCode the code to use to look up the "detail" field
|
||||
* through a {@code MessageSource}, falling back on
|
||||
* {@link ErrorResponse#getDefaultDetailMessageCode(Class, String)}
|
||||
* @param detailMessageArguments the arguments to go with the detailMessageCode
|
||||
* @return the created {@code ProblemDetail} instance
|
||||
*/
|
||||
protected ProblemDetail createProblemDetail(
|
||||
Exception ex, HttpStatusCode status, @Nullable HttpHeaders headers,
|
||||
String defaultDetail, @Nullable String detailMessageCode, @Nullable Object[] detailMessageArguments,
|
||||
ServerWebExchange exchange) {
|
||||
|
||||
ErrorResponse response = ErrorResponse.createFor(
|
||||
ex, status, headers, defaultDetail, detailMessageCode, detailMessageArguments);
|
||||
|
||||
return response.updateAndGetBody(this.messageSource, getLocale(exchange));
|
||||
}
|
||||
|
||||
private static Locale getLocale(ServerWebExchange exchange) {
|
||||
Locale locale = exchange.getLocaleContext().getLocale();
|
||||
return (locale != null ? locale : Locale.getDefault());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal handler method that all others in this class delegate to, for
|
||||
* common handling, and for the creation of a {@link ResponseEntity}.
|
||||
@@ -311,7 +340,7 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
|
||||
* @return a {@code Mono} with the {@code ResponseEntity} for the response
|
||||
*/
|
||||
protected Mono<ResponseEntity<Object>> handleExceptionInternal(
|
||||
Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatusCode status,
|
||||
Exception ex, @Nullable Object body, @Nullable HttpHeaders headers, HttpStatusCode status,
|
||||
ServerWebExchange exchange) {
|
||||
|
||||
if (exchange.getResponse().isCommitted()) {
|
||||
@@ -319,25 +348,12 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
|
||||
}
|
||||
|
||||
if (body == null && ex instanceof ErrorResponse errorResponse) {
|
||||
body = resolveDetailViaMessageSource(errorResponse, exchange.getLocaleContext().getLocale());
|
||||
body = errorResponse.updateAndGetBody(this.messageSource, getLocale(exchange));
|
||||
}
|
||||
|
||||
return createResponseEntity(body, headers, status, exchange);
|
||||
}
|
||||
|
||||
private ProblemDetail resolveDetailViaMessageSource(ErrorResponse response, @Nullable Locale locale) {
|
||||
ProblemDetail body = response.getBody();
|
||||
if (this.messageSource != null) {
|
||||
locale = (locale != null ? locale : Locale.getDefault());
|
||||
Object[] arguments = response.getDetailMessageArguments(this.messageSource, locale);
|
||||
String detail = this.messageSource.getMessage(response.getDetailMessageCode(), arguments, null, locale);
|
||||
if (detail != null) {
|
||||
body.setDetail(detail);
|
||||
}
|
||||
}
|
||||
return body;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the {@link ResponseEntity} to use from the given body, headers,
|
||||
* and statusCode. Subclasses can override this method to inspect and possibly
|
||||
@@ -351,7 +367,8 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
|
||||
* @since 6.0
|
||||
*/
|
||||
protected Mono<ResponseEntity<Object>> createResponseEntity(
|
||||
@Nullable Object body, HttpHeaders headers, HttpStatusCode status, ServerWebExchange exchange) {
|
||||
@Nullable Object body, @Nullable HttpHeaders headers, HttpStatusCode status,
|
||||
ServerWebExchange exchange) {
|
||||
|
||||
return Mono.just(new ResponseEntity<>(body, headers, status));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user