1. 程式人生 > >Hibernate Validator 6.0.7.Final 之一(宣告Bean約束之容器元素的約束)

Hibernate Validator 6.0.7.Final 之一(宣告Bean約束之容器元素的約束)

  首先,我們需要知道什麼是容器元素–其實就是List、Set、Map等。我們也知道,使用容器元素的時候,需要指定容器能容納的資料的型別,例如,List<String>就是說這個List容器可以容納String型別,這裡的String叫做引數化型別。本文要講的就是對引數化型別約束。
  需要注意的是,如果想要將一個約束應用到引數化型別上,那麼這個約束的定義中的@Target中必須包含ElementType.TYPE_USE。什麼意思呢?我們以validator-api標準的非空約束為例解釋一下。從該約束的定義中我們可以看到它的@Target中包含了TYPE_USE這個值,由此,我們知道@NotNull約束可以被應用到引數化型別上。

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {

    String message() default "{javax.validation.constraints.NotNull.message}";

    Class<?>[] groups() default
{ }; Class<? extends Payload>[] payload() default { }; /** * Defines several {@link NotNull} annotations on the same element. * * @see javax.validation.constraints.NotNull */ @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) @Retention
(RUNTIME) @Documented @interface List { NotNull[] value(); } }

  截止Bean Validation 2.0,Bean Validation(JSR標準)內建的和Hibernate Validator(JSR標準的實現)特有的約束都指定了ElementType.TYPE_USE。所以,我們可以直接在引數化型別上使用這些約束。但是,如果想要在引數化型別上使用自定義的約束,一定記得將ElementType.TYPE_USE加到自定義的約束上。
  內建的受支援的容器元素有這些:java.util.Iterable的實現(List、Set等)、java.util.Map的實現、java.util.Optional、java.util.OptionalInt、java.util.OptionalDouble、java.util.OptionalLong等。自定義的容器元素的約束本文不講。


  下面,我們以Set為例子來感性認識一下容器約束。

public class Car {

    private Set<@NotNull String> parts = new HashSet<>();

    public Set<String> getParts() {
        return parts;
    }

    public void setParts(Set<String> parts) {
        this.parts = parts;
    }
}
    @Test
    public void setTest() {
        Car car = new Car();

        Set<String> parts = new HashSet<>();
        parts.add("wheel");// 沒問題
        parts.add("");// 沒問題
        parts.add(null);// 有問題

        car.setParts(parts);

        Set<ConstraintViolation<Car>> constraintViolations = validator.validate(car);
        logger.info("違反的約束的個數:{}", constraintViolations.size());
        for (ConstraintViolation<Car> constraintViolation : constraintViolations) {
            logger.info("違反的約束:{}, {}", constraintViolation.getExecutableReturnValue(),
                    constraintViolation.getMessage());
        }
    }
INFO [main] com.qs.mmeng.hibernate.validator.constraints.container.ContainerElementConstraintTest.setTest : 違反的約束的個數:1
INFO [main] com.qs.mmeng.hibernate.validator.constraints.container.ContainerElementConstraintTest.setTest : 違反的約束:null, 不能為null

當然,這個例子非常簡單,其他的容器元素也都是類似的。