Files
recipe-api/src/main/java/eu/bitfield/recipes/api/ErrorResponseHandling.java

114 lines
4.6 KiB
Java

package eu.bitfield.recipes.api;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.core.MethodParameter;
import org.springframework.http.ProblemDetail;
import org.springframework.util.MultiValueMap;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.validation.method.ParameterValidationResult;
import org.springframework.web.ErrorResponse;
import org.springframework.web.ErrorResponseException;
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.ServerWebInputException;
import java.lang.reflect.Executable;
import java.lang.reflect.Parameter;
import java.util.List;
import static eu.bitfield.recipes.util.CollectionUtils.*;
import static org.springframework.http.HttpStatus.*;
public interface ErrorResponseHandling {
Logger log = LoggerFactory.getLogger(ErrorResponseHandling.class);
private static void addMethodParameter(ProblemDetail problemDetail, MethodParameter methodParam) {
Executable executable = methodParam.getExecutable();
Parameter param = methodParam.getParameter();
String method = executable.toGenericString();
String argument = param.getType().getCanonicalName() + " " + param.getName();
problemDetail.setProperty("method", method);
problemDetail.setProperty("argument", argument);
}
@ExceptionHandler
default ErrorResponse handleError(HandlerMethodValidationException e) {
log.debug("""
Handling {}:
method: {}
errors: {}""",
e.getClass().getName(), e.getMethod(), e.getAllErrors(), e);
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST, e.getReason());
String method = e.getMethod().toGenericString();
problemDetail.setProperty("method", method);
MultiValueMap<String, String> errors = multiValueMap();
for (ParameterValidationResult result : e.getParameterValidationResults()) {
Parameter param = result.getMethodParameter().getParameter();
String errorKey = param.getName();
List<String> errorValues = result.getResolvableErrors()
.stream()
.map(MessageSourceResolvable::getDefaultMessage)
.toList();
errors.addAll(errorKey, errorValues);
}
problemDetail.setProperty("errors", errors);
return ErrorResponse.builder(e, problemDetail).build();
}
@ExceptionHandler
default ErrorResponse handleError(WebExchangeBindException e) {
List<ObjectError> objectErrors = e.getAllErrors();
log.debug("""
Handling {}:
methodParameter: {}
errors: {}""",
e.getClass().getName(), e.getMethodParameter(), e.getAllErrors(), e);
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST, e.getReason());
MethodParameter methodParam = e.getMethodParameter();
if (methodParam != null) addMethodParameter(problemDetail, methodParam);
MultiValueMap<String, String> errors = multiValueMap();
for (ObjectError objectError : objectErrors) {
String errorKey = objectError.getObjectName();
if (objectError instanceof FieldError fieldError) {
errorKey += "." + fieldError.getField();
}
errors.add(errorKey, objectError.getDefaultMessage());
}
problemDetail.setProperty("errors", errors);
return ErrorResponse.builder(e, problemDetail).build();
}
@ExceptionHandler
default ErrorResponse handleError(ServerWebInputException e) {
log.debug("""
Handling {}:
methodParameter: {}""",
e.getClass().getName(), e.getMethodParameter(), e);
ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST, e.getReason());
MethodParameter methodParam = e.getMethodParameter();
if (methodParam != null) addMethodParameter(problemDetail, methodParam);
return ErrorResponse.builder(e, problemDetail).build();
}
@ExceptionHandler
default ErrorResponse handleError(ErrorResponseException e) {
log.debug("Handling {}", e.getClass().getName(), e);
return e;
}
}