当前日期时间不应通过使用@Past 注释的验证

Current datetime shouldnt pass the validation using @Past annotation

当字段设置为 now 时,我需要 @Past 来出错。我意识到字段上的 now 值和验证器比较时使用的 now 值会略有不同,因此需要在休眠验证器中设置容差。

问题是我无法让它工作。这是 junit:

@Test
public void testHibernateValidator_withPast_withTodayDate() {
    // populates with 'now'
    MyFormWithPast form = new MyFormWithPast();
    form.setDt(OffsetDateTime.now(Clock.systemUTC()));

    ValidatorFactory factory = Validation.byProvider(HibernateValidator.class)
            .configure()
            .clockProvider(() -> Clock.systemUTC())
            // adds tolerance so that when comparing, the form dt and 'now' is considered equal, 
            //   therefore dt is not a past datetime
            .temporalValidationTolerance(Duration.ofMinutes(1))
            .buildValidatorFactory();

    Validator validator = factory.getValidator();
    Set<ConstraintViolation<MyFormWithPast>> errors = validator.validate(form);

    // needs to fail, since 'now' shouldn't be considered 'past'
    assertFalse("now shoudnt be considered as Past", errors.isEmpty());
}

public static class MyFormWithPast {
    @Past
    private OffsetDateTime dt;

    public void setDt(OffsetDateTime dt) {
        this.dt = dt;
    }

    public OffsetDateTime getDt() {
        return dt;
    }
}

我希望在字段中输入 'now' 时验证失败,因为 'now' 不应被视为 'past'。我错过了什么?

时间验证容差被设计得更宽松,而不是更严格。你希望它更严格。

我认为你需要自己的约束来处理你想做的事情。

只想分享我当前的解决方案,添加 1 分钟的默认前向公差,以便输入 'now' 不被视为 'past'。

注解:

/**
 * Validates that the date is of the past, with forward tolerance of 1 minute, 
 *   to offset the time to create a 'now' instance to compare to.
 * The usage is when user selects 'today' in the UI, we dont want it to be considered as 'Past'
 * 
 * Annotation is applicable to {@link OffsetDateTime}.
 */
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy=StrictPastValidator.class)
public @interface StrictPast {

    public static final String MESSAGE = "{constraints.StrictPast.message}";

    /**
     * @return The error message template.
     */
    String message() default MESSAGE;

    /**
     * @return The groups the constraint belongs to.
     */
    Class<?>[] groups() default { };

    /**
     * @return The payload associated to the constraint
     */
    Class<? extends Payload>[] payload() default {};

}

验证者:

public class StrictPastValidator implements ConstraintValidator<StrictPast, Object> {

    @Override
    public void initialize(StrictPast annotation) {
    }

    @Override
    public boolean isValid(Object input, ConstraintValidatorContext ignored) {
        if (input == null) {
             return true;
        } else if (input instanceof OffsetDateTime) {
            return isValidOffsetDateTime((OffsetDateTime) input);
        }
        throw new IllegalStateException("StrictPastValidator is not applicable to the field type " + input.getClass().getName());
    }

    private boolean isValidOffsetDateTime(OffsetDateTime input) {
        OffsetDateTime plusSecondsDt = input.plusSeconds(Duration.ofMinutes(1).getSeconds());
        return plusSecondsDt.isBefore(OffsetDateTime.now(Clock.systemUTC()));
    }

}