Add default web handling of method validation errors

Closes gh-30644
This commit is contained in:
rstoyanchev
2023-06-30 16:09:33 +01:00
parent a481c7649f
commit 7a79da589a
10 changed files with 339 additions and 63 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2022 the original author or authors.
* Copyright 2002-2023 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -25,15 +25,18 @@ import reactor.core.publisher.Mono;
import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.validation.beanvalidation.MethodValidationException;
import org.springframework.web.ErrorResponse;
import org.springframework.web.ErrorResponseException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.method.annotation.HandlerMethodValidationException;
import org.springframework.web.server.MethodNotAllowedException;
import org.springframework.web.server.MissingRequestValueException;
import org.springframework.web.server.NotAcceptableStatusException;
@@ -97,10 +100,12 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
MissingRequestValueException.class,
UnsatisfiedRequestParameterException.class,
WebExchangeBindException.class,
HandlerMethodValidationException.class,
ServerWebInputException.class,
ServerErrorException.class,
ResponseStatusException.class,
ErrorResponseException.class
ErrorResponseException.class,
MethodValidationException.class
})
public final Mono<ResponseEntity<Object>> handleException(Exception ex, ServerWebExchange exchange) {
if (ex instanceof MethodNotAllowedException theEx) {
@@ -121,6 +126,9 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
else if (ex instanceof WebExchangeBindException theEx) {
return handleWebExchangeBindException(theEx, theEx.getHeaders(), theEx.getStatusCode(), exchange);
}
else if (ex instanceof HandlerMethodValidationException theEx) {
return handleHandlerMethodValidationException(theEx, theEx.getHeaders(), theEx.getStatusCode(), exchange);
}
else if (ex instanceof ServerWebInputException theEx) {
return handleServerWebInputException(theEx, theEx.getHeaders(), theEx.getStatusCode(), exchange);
}
@@ -133,6 +141,9 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
else if (ex instanceof ErrorResponseException theEx) {
return handleErrorResponseException(theEx, theEx.getHeaders(), theEx.getStatusCode(), exchange);
}
else if (ex instanceof MethodValidationException theEx) {
return handleMethodValidationException(theEx, HttpStatus.INTERNAL_SERVER_ERROR, exchange);
}
else {
if (logger.isWarnEnabled()) {
logger.warn("Unexpected exception type: " + ex.getClass().getName());
@@ -237,6 +248,23 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
return handleExceptionInternal(ex, null, headers, status, exchange);
}
/**
* Customize the handling of {@link HandlerMethodValidationException}.
* <p>This method delegates to {@link #handleExceptionInternal}.
* @param ex the exception to handle
* @param headers the headers to use for the response
* @param status the status code to use for the response
* @param exchange the current request and response
* @return a {@code Mono} with the {@code ResponseEntity} for the response
* @since 6.1
*/
protected Mono<ResponseEntity<Object>> handleHandlerMethodValidationException(
HandlerMethodValidationException ex, HttpHeaders headers, HttpStatusCode status,
ServerWebExchange exchange) {
return handleExceptionInternal(ex, null, headers, status, exchange);
}
/**
* Customize the handling of {@link ServerWebInputException}.
* <p>This method delegates to {@link #handleExceptionInternal}.
@@ -301,6 +329,22 @@ public abstract class ResponseEntityExceptionHandler implements MessageSourceAwa
return handleExceptionInternal(ex, null, headers, status, exchange);
}
/**
* Customize the handling of {@link MethodValidationException}.
* <p>This method delegates to {@link #handleExceptionInternal}.
* @param ex the exception to handle
* @param status the status code to use for the response
* @param exchange the current request and response
* @return a {@code Mono} with the {@code ResponseEntity} for the response
* @since 6.1
*/
protected Mono<ResponseEntity<Object>> handleMethodValidationException(
MethodValidationException ex, HttpStatus status, ServerWebExchange exchange) {
ProblemDetail body = createProblemDetail(ex, status, "Validation failed", null, null, exchange);
return handleExceptionInternal(ex, body, null, status, exchange);
}
/**
* Convenience method to create a {@link ProblemDetail} for any exception
* that doesn't implement {@link ErrorResponse}, also performing a