简体   繁体   中英

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 :(

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);
    }
}

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 .

I found the problem, the controller advice were put in common util module, which does not seem to be used by Spring, though it was under the same base package of component scanning. What I did is overriding methods from ResponseEntityExceptionHandler in a global abstract class (in common module), then in other module just extended that class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM