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

问题描述 投票:0回答:2

当字段设置为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;
    }
}

我希望在字段中输入“现在”时验证会失败,因为“现在”不应被视为“过去”。我想念什么?

bean-validation hibernate-validator
2个回答
1
投票

时间验证容忍度设计得更宽松,而不是更严格。您希望它更严格。

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


0
投票

只想分享我当前的解决方案,添加默认的1分钟正向公差,以便输入的“现在”不被视为“过去”。

注解:

/**
 * 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'
 * https://stackoverflow.com/questions/60341963/current-datetime-shouldnt-pass-the-validation-using-past-annotation
 * 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()));
    }

}
© www.soinside.com 2019 - 2024. All rights reserved.