From 3ff8cce30243791b74940764175f23a203ac8abe Mon Sep 17 00:00:00 2001 From: aherbst-broad Date: Mon, 5 Aug 2024 12:39:59 -0400 Subject: [PATCH] [WOR-1798] Indicate which fields are missing when giving back a 400 on MethodArgumentNotValidException --- .../controller/GlobalExceptionHandler.java | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/service/src/main/java/bio/terra/workspace/app/controller/GlobalExceptionHandler.java b/service/src/main/java/bio/terra/workspace/app/controller/GlobalExceptionHandler.java index b3b763d3dd..47021f1de6 100644 --- a/service/src/main/java/bio/terra/workspace/app/controller/GlobalExceptionHandler.java +++ b/service/src/main/java/bio/terra/workspace/app/controller/GlobalExceptionHandler.java @@ -4,6 +4,7 @@ import bio.terra.common.exception.NotFoundException; import bio.terra.workspace.generated.model.ApiErrorReport; import jakarta.validation.ConstraintViolationException; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import org.slf4j.Logger; @@ -12,6 +13,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.retry.backoff.BackOffInterruptedException; +import org.springframework.validation.FieldError; +import org.springframework.validation.ObjectError; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; @@ -44,7 +47,6 @@ public ResponseEntity errorReportHandler(ErrorReportException ex // -- validation exceptions - we don't control the exception raised @ExceptionHandler({ - MethodArgumentNotValidException.class, MethodArgumentTypeMismatchException.class, HttpMessageNotReadableException.class, HttpRequestMethodNotSupportedException.class, @@ -67,6 +69,31 @@ public ResponseEntity validationExceptionHandler(Exception ex) { return new ResponseEntity<>(errorReport, HttpStatus.BAD_REQUEST); } + /** Give back the fields missing from the request that caused the exception. */ + @ExceptionHandler({MethodArgumentNotValidException.class}) + public ResponseEntity methodArgNotValidHandler( + MethodArgumentNotValidException ex) { + final List errors = new ArrayList<>(); + for (final FieldError error : ex.getBindingResult().getFieldErrors()) { + errors.add(error.getField() + ": " + error.getDefaultMessage()); + } + for (final ObjectError error : ex.getBindingResult().getGlobalErrors()) { + errors.add(error.getObjectName() + ": " + error.getDefaultMessage()); + } + + String validationErrorMessage = + "Request could not be parsed or was invalid: " + + ex.getClass().getSimpleName() + + ". Ensure that all types are correct and that enums have valid values."; + ApiErrorReport errorReport = + new ApiErrorReport() + .message(validationErrorMessage) + .statusCode(HttpStatus.BAD_REQUEST.value()) + .causes(errors); + + return new ResponseEntity<>(errorReport, HttpStatus.BAD_REQUEST); + } + @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity constraintViolationExceptionHandler( ConstraintViolationException ex) {