package com.cassiomolin.patch.web.exception; import com.cassiomolin.patch.web.resource.error.ApiError; import com.cassiomolin.patch.web.resource.error.ApiResourcePropertyError; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.context.request.WebRequest; import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.util.List; import java.util.stream.Stream; import static java.util.stream.Collectors.toList; @ControllerAdvice public class WebApiExceptionHandler extends ResponseEntityExceptionHandler { @Override protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers, HttpStatus status, WebRequest request) { List<String> globalErrors = ex.getBindingResult().getGlobalErrors() .stream() .map(error -> error.getObjectName() + ": " + error.getDefaultMessage()) .collect(toList()); List<ApiResourcePropertyError> fieldErrors = ex.getBindingResult().getFieldErrors() .stream() .map(this::toResourcePropertyError) .collect(toList()); ApiError apiError = ApiError.builder() .message("Validation error") .status(ex.getParameter().hasParameterAnnotation(RequestBody.class) ? HttpStatus.UNPROCESSABLE_ENTITY : HttpStatus.BAD_REQUEST) .details(Stream.concat(globalErrors.stream(), fieldErrors.stream()).collect(toList())) .build(); return handleExceptionInternal(ex, apiError, headers, apiError.getStatus(), request); } @ExceptionHandler(ConstraintViolationException.class) public ResponseEntity<Object> handleConstraintViolation(ConstraintViolationException ex, WebRequest request) { List<ApiResourcePropertyError> errors = ex.getConstraintViolations() .stream() .map(this::toResourcePropertyError) .collect(toList()); ApiError apiError = ApiError.builder() .message("Validation error") .status(HttpStatus.UNPROCESSABLE_ENTITY) .details(errors) .build(); return handleExceptionInternal(ex, apiError, new HttpHeaders(), apiError.getStatus(), request); } private ApiResourcePropertyError toResourcePropertyError(ConstraintViolation violation) { return ApiResourcePropertyError.builder() .property(violation.getPropertyPath().toString()) .message(violation.getMessage()) .invalidValue(violation.getInvalidValue()) .build(); } private ApiResourcePropertyError toResourcePropertyError(FieldError fieldError) { return ApiResourcePropertyError.builder() .property(fieldError.getField()) .message(fieldError.getDefaultMessage()) .invalidValue(fieldError.getRejectedValue()) .build(); } }