Валидатор ограничения уровня метода не выполнен - PullRequest
0 голосов
/ 06 января 2020

Я делаю проверку в своем классе Spring REST Controller. Мой пользовательский валидатор ограничений не выполняется, если нарушение самого ограничения происходит с самим объектом аргумента.

Ожидание

Запрос:

{
  fieldA: "2020-01-05",
  fieldB: "2020-01-02",
  fieldC: ""
}

Ответ:

{
  errors: [
    "Field C is mandatory",
    "Invalid date range"
  ]
}

В настоящее время - сценарий 1

Запрос:

{
  fieldA: "2020-01-05",
  fieldB: "2020-01-02",
  fieldC: ""
}

Ответ:

{
  errors: [
    "Field C is mandatory"
  ]
}

В настоящее время - сценарий 2

Запрос:

{
  fieldA: "2020-01-05",
  fieldB: "2020-01-02",
  fieldC: "<some-value>"
}

Ответ:

{
  errors: [
    "Invalid date range."
  ]
}

Вот фрагмент кода

SomeAPI . java

@RestController
@RequestMapping(value = "/")
@Validated
public class SomeAPI {

    @PostMapping
    @SomeValidation
    public ResponseEntity<Map<String, Object>> saveSomething(@Valid @RequestBody SomeForm form) {
        return new ResponseEntity<>(responseBody, HttpStatus.CREATED);
    }

}

SomeForm. java

public class SomeForm {

  @NotNull(message = "Field A is mandatory")
    private LocalDate fieldA;

  @NotNull(message = "Field B is mandatory")
    private LocalDate fieldB;

  @NotBlank(message = "Field C is mandatory")
    private String fieldC;

  // Setters and getters

}

SomeValidation. java

@Documented
@Constraint(validatedBy = SomeValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD })
public @interface SomeValidation {

  String message() default "";

  Class<?>[] groups() default {};

  Class<? extends Payload>[] payload() default {};

}

@SupportedValidationTarget(ValidationTarget.PARAMETERS)
class SomeValidator implements ConstraintValidator<SomeValidation, Object[]> {

  private static Logger logger = LoggerFactory.getLogger(SomeValidator.class);

  @Override
  public boolean isValid(Object[] value, ConstraintValidatorContext context) {
    context.disableDefaultConstraintViolation();
    SomeForm form = (SomeForm) value[0];
    boolean valid = true;
    if (!isValid(form)) {
      valid = false;
      context.buildConstraintViolationWithTemplate("Invalid date range").addConstraintViolation();
    }
    return valid;
  }

  private boolean isValid(SomeForm form) {
    logger.info("isValid");
    return form.getFieldA().isBefore(form.getFieldB());
  }

}

APIExceptionHandler. java

@ControllerAdvice
public class APIExceptionHandler extends ResponseEntityExceptionHandler {

    private static final String TIMESTAMP_KEY = "timestamp";
    private static final String STATUS_KEY = "status";
    private static final String ERRORS_KEY = "errors";

    @Override
    protected ResponseEntity<Object> handleBindException(BindException ex, HttpHeaders headers, HttpStatus status,
            WebRequest request) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put(TIMESTAMP_KEY, new Date());
        body.put(STATUS_KEY, status.value());
        List<String> errors = ex.getBindingResult().getFieldErrors().stream().map(FieldError::getDefaultMessage)
                .collect(Collectors.toList());
        body.put(ERRORS_KEY, errors);
        return new ResponseEntity<>(body, headers, status);
    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex, HttpHeaders headers,
            HttpStatus status, WebRequest request) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put(TIMESTAMP_KEY, new Date());
        body.put(STATUS_KEY, status.value());
        List<String> errors = ex.getBindingResult().getAllErrors().stream().map(ObjectError::getDefaultMessage)
                .collect(Collectors.toList());
        body.put(ERRORS_KEY, errors);
        return new ResponseEntity<>(body, headers, status);
    }

    @ExceptionHandler({ ConstraintViolationException.class })
    public ResponseEntity<Object> handleConstraintViolation(final ConstraintViolationException ex,
            final WebRequest request) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put(TIMESTAMP_KEY, new Date());
        body.put(STATUS_KEY, HttpStatus.BAD_REQUEST.value());
        List<String> errors = ex.getConstraintViolations().stream().map(ConstraintViolation::getMessage)
                .collect(Collectors.toList());
        body.put(ERRORS_KEY, errors);
        return new ResponseEntity<>(body, new HttpHeaders(), HttpStatus.BAD_REQUEST);
    }

}
...