如何为同一个 属性 节点添加多个约束违规?

How to add multiple constraint violations for the same property node?

我有一个习惯ConstraintValidator。我想要做的是为相同的 属性 节点添加多个约束违规,具有相同的消息和不同的动态有效负载。这可能吗?

自定义注释:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CustomFieldConstraintValidator.class)
public @interface CustomFieldConstraint {
    String message() default "message";

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

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

自定义约束验证器:

public class CustomFieldConstraintValidator implements ConstraintValidator<CustomFieldConstraint, Integer> {
    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
        var valid = true;
        var hibernateConstraintValidatorContext = context.unwrap(HibernateConstraintValidatorContext.class);
        hibernateConstraintValidatorContext.disableDefaultConstraintViolation();

        if (value > 0) {
            valid = false;

            hibernateConstraintValidatorContext.withDynamicPayload(Map.of("must_be_less_than", 0))
                .buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                .addPropertyNode("field")
                .addConstraintViolation();
        }

        if (value > 5) {
            valid = false;

            hibernateConstraintValidatorContext.withDynamicPayload(Map.of("must_be_less_than", 5))
                .buildConstraintViolationWithTemplate(context.getDefaultConstraintMessageTemplate())
                .addPropertyNode("field")
                .addConstraintViolation();
        }

        return valid;
    }
}

验证器测试:

public class HibernateValidatorTest {
    private final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();

    @Test
    void multipleFailuresForSameField() {
        var foo = new Foo(10);

        var constraintViolations = validator.validate(foo);

        assertEquals(2, constraintViolations.size());
    }

    public static class Foo {
        @CustomFieldConstraint
        private int field;

        public Foo(int field) {
            this.field = field;
        }
    }
}

测试失败 expected: <2> but was: <1>

您遇到此问题是因为 ConstraintViolation 作为一个集合返回,并且根据设计,动态负载不包含在 equals() 方法中。参见 https://github.com/hibernate/hibernate-validator/blob/master/engine/src/main/java/org/hibernate/validator/internal/engine/ConstraintViolationImpl.java#L251

因此您的 2 个约束在集合级别被认为是相等的。

您需要改变做事的方式,并用这两种信息来丰富负载。