Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring boot REST validation error response

Controller method:

public Mission createMission(final @Valid @RequestBody Mission mission) {

    //save..

    return mission;
}

I want to enumerate all validation error messages as json and return.

I can do that with creating a new exception class, adding BindingResult in controller method param, throwing the new exception when binding result has error and handling the exception in @ControllerAdvice class.

if (bindingResult.hasErrors()) {
        throw new InvalidRequestException("Fix input and try again", bindingResult);
    }

But I want to avoid checking BindingResult in each controller method, rather handle globally. I could have done that if I could handle exception: org.springframework.web.bind.MethodArgumentNotValidException. But unfortunately Spring boot does not allow

@ExceptionHandler(MethodArgumentNotValidException.class)

it shows ambiguous exception handler, as the same exception is handled ResponseEntityExceptionHandler, and I can't override handleException as it is final. I tried overriding protected ResponseEntity handleMethodArgumentNotValid() by catching Exception.class, but that does not get called at all.

Is there any way to achieve this goal? it seems like lots of things for a simple task :(

like image 366
Shafiul Avatar asked Jan 05 '17 09:01

Shafiul


2 Answers

You should create a class that use @ControllerAdvice and extends ResponseEntityExceptionHandler. Then you can override the method handleMethodArgumentNotValid. You can use something like that:

@ControllerAdvice
public class RestResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {

@Override
@ResponseStatus(HttpStatus.BAD_REQUEST)
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
    final List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
    Map <String, Set<String>> errorsMap =  fieldErrors.stream().collect(
            Collectors.groupingBy(FieldError::getField,
                    Collectors.mapping(FieldError::getDefaultMessage, Collectors.toSet())
            )
    );
    return new ResponseEntity(errorsMap.isEmpty()? ex:errorsMap, headers, status);
    }
}
like image 140
Joan Sebastián Ramírez Pérez Avatar answered Nov 18 '22 14:11

Joan Sebastián Ramírez Pérez


If you don't want to extend to ResponseEntityExceptionHandler, you need to annotate your GlobalExceptionHandler to @ControllerAdvice and @ResponseBody.

Update: Spring Boot created a new annotation @RestControllerAdvice in combination of @ControllerAdvice and @ResponseBody.

like image 38
Catalino Comision Avatar answered Nov 18 '22 13:11

Catalino Comision