本文主要讲解了约束的两种继承方式和对象图,也就是级联属性中的约束注解:包括引用的对象和集合中的元素。

一、约束继承

当一个类实现来了一个接口,或者是存在的 另一个类,则所有的被声明在父类中的约束注解,会以相同的方式,应用在当前子类上。为了清晰的展示约束注解,来看看下面这个例子。

被继承的父类:

public class Car {

private String manufacturer;

@NotNull
public String getManufacturer() {
return manufacturer;
    }

public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
    }

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this,
        ToStringStyle.SHORT_PREFIX_STYLE);
    }
}

图中的注解为@NotNull,作用是约束getManufacturer()的返回值是非空的。下面来看继承它的子类:

public class RentalCar extends Car {

private String rentalStation;

@NotNull
public String getRentalStation() {
return rentalStation;
  }

//...
}

这里RentalCar类是Car类的子类,并且增加了属性rentalStation。

如果一个RentalCar实例被验证了,不但在rentalStation上的@NotNull注解约束会起作用,也包括在父类中的manufacturer上的注解约束。

同样的,如果Car不是一个类,而是一个接口,然后被RentalCar实现,那么Car接口中的注解约束,也会在RentalCar上起作用。

如果方法被重写的话,约束注解会被聚合在一起。所以如果RentalCar重写了父类Car中的getManufacturer()方法,那么加在这个方法上的任何注解,都会把父类中的@NotNull注解,也聚合在自己上面。

二、对象图

Bean Validation API不但允许验证单个类的实例,而且还允许完整的对象图(级联验证)。

为了达到这一目的,仅仅只是注解一个成员变量,或是属性。该成员变量或属性引用另外一个带有@Valid注解的对象。

例2.11 “级联验证”:

public class Car {

@NotNull
@Valid
private Person driver;

//...
}
public class Person {

@NotNull
private String name;

//...
}

如果一个Car实例被验证,那么它引用的Person对象,同时也会被验证。

因为这个driver成员变量加上了@Valid注解,所以如果这个引用的person对象中的name成员变量是null的话,那么这个Car验证也会失败。

对象的验证是递归的,也就是说,如果一个引用被标记为级联验证,指向一个对象。而该对象本身有属性加上了@Valid注解,那么这些引用同时也会被验证引擎跟进。

这个验证引擎将会确保,没有无限死循环的级联验证。比如,两个对象相互引用。还要注意,null值在级联验证期间会被忽略。

作为约束,对象图的验证,也可以对容器元素起作用。这意味着,任何类型的容器中的元素,都可以加上@Valid注解。当父对象被验证的时候,每一个被包含的元素都会被验证。

级联验证也支持嵌套容器元素,下面看例2.12:

public class Car {

private List<@NotNull @Valid Person> passengers = 
new ArrayList<Person>();

private Map<@Valid Part, List<@Valid Manufacturer>> partManufacturers 
            = new HashMap<>();
//...
}

public class Part {

@NotNull
private String name;

//...
}

public class Manufacturer {

@NotNull
private String name;

//...
}

在例2.12容器的级联验证中,当验证一个Car实例的时候,一个ConstraintViolation将会被创建:

  • 如果包含在passengers list中的任何一个Person对象有一个null名字的话;
  • 如果包含在map keys中的任何一个Part对象有一个null名字的话;
  • 如果包含在嵌套map value中的任何一个Manufacturer对象有一个null名字的话。

在版本6之前,Hibernate validator支持级联验证对于容器元素中的子集。它实现在容器级别(例如,你需要用@Valid private List<person> 去激活级联验证Person)。</person>

在现有版本中,这将不再被推荐使用。请使用容器元素级别的@Valid注解,因为它更有表现力。

今天的讲解就到这里了,后面会讲解验证Bean的约束。