Bean Validation的1.0版本
1、约束定义
1.1 约束注解
Constraint 可用于字段、方法、属性、类型、注解类型,validatedBy返回的是ConstraintValidator类型的数组
@Documented
@Target({ ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface Constraint {
/**
* <code>ConstraintValidator</code> classes must reference distinct target types.
* If two <code>ConstraintValidator</code> refer to the same type,
* an exception will occur.
*
* @return array of ConstraintValidator classes implementing the constraint
*/
public Class<? extends ConstraintValidator<?, ?>>[] validatedBy();
}
约束的属性有三个基本的
String message() default '';
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
1.2 应用相同类型的多个约束
使用常规注解,value返回元素类型为约束注解的数组,并且注解的保留策略必须是RUNTIME。@Target 建议与初始约束有相同。
建议约束注解与多值注解耦合在一起
1.3 约束组合
组合注解继承主约束注解的分组和payload
主注解如果想覆盖组合注解的属性,可以使用@OverridesAttribute或者@OverridesAttribute.List
@Retention(RUNTIME)
@Target({ METHOD })
public @interface OverridesAttribute {
/**
* @return Constraint type the attribute is overriding
*/
Class<? extends Annotation> constraint();
/**
* Name of the Constraint attribute overridden.
* Defaults to the name of the attribute hosting <code>@OverridesAttribute</code>.
*
* @return name of constraint attribute overridden.
*/
String name();
/**
* The index of the targeted constraint declaration when using
* multiple constraints of the same type.
* The index represents the index of the constraint in the value() array.
*
* By default, no index is defined and the single constraint declaration
* is targeted
*
* @return constraint declaration index if multivalued annotation is used
*/
int constraintIndex() default -1;
/**
* Defines several @OverridesAttribute annotations on the same element
* @see javax.validation.OverridesAttribute
*/
@Documented
@Target({ METHOD })
@Retention(RUNTIME)
public @interface List {
OverridesAttribute[] value();
}
}
1.4 约束校验实现
通过注解@Contraint(validatedBy=<class>)指定
class需要实现ConstraintValidator泛型接口
T不能是参数化类型或者T的泛型参数必须是无界通配符
相关类图:
2、约束声明及校验处理
约束在类型上声明,评估实例或者实例图。
2.1 待验证类的要求
- 属性需要遵循JavaBean读取属性的方法签名约定
- 静态字段和方法不在校验范围内
- 约束可以用于接口和超类
注解定义的目标可以是字段,属性或者类型,前提是:
- 约束定义支持指定的目标类型(java.lang.annotation.Target)
- 约束中声明的其中一个ConstraintValidator支持声明的目标类型
2.1.1 对象验证
约束声明用于类或者接口上。对类或接口应用约束表示对类或实现接口的类的状态的验证
2.1.2 字段和属性验证
约束声明可以应用于同一类型的字段和属性上。在字段和相关属性上同一约束不应该重复。推荐持有约束声明的对象绑定到单状态访问策略。
字段和方法的可见性不受约束。
2.1.3 图验证
图的结果验证作为一组统一的约束冲突返回。使用@Valid注解。
集合、数组、迭代器的字段和属性也可以用@Valid装饰。
2.2 约束声明
约束声明通过注解放在类或者接口上。约束注解可以应用于类型上、类型字段以及遵循JavaBean的属性上。
约束声明定义在类上,需要验证的类实例会传递给ConstraintValidator。
约束定义在字段上,字段值传递给ConstraintValidator
约束定义在getter方法上,getter方法的返回值传递给ConstraintValidator
2.3 继承(接口和超类)
约束声明放在接口上,对于给定类,约束声明放在超类上。
约束声明的影响是累加的。将验证在超类getter上声明的约束以及根据Java语言规范可见性规则在getter的重写版本上定义的任何约束
2.4 组和组序列
组定义约束子集。不是验证给定对象图的所有约束,只是验证其中的子集。子集通过目标组或者组群定义。每个约束声明定义所属的组列表。如果没有指定,属于Default组。
组由接口表示。
约束可以属于一个或者多个组。
2.4.1 组继承
在某些情况下,组是一个或者多个组的超集。组可以通过接口继承来继承一个或者多个组。
2.4.2 组序列
默认情况下,不管属于哪个组,约束检查没有固定的顺序。
通过注解@GroupSequence来指定次序。
组的组合不应该有环依赖。如果包含环依赖,验证计算时会抛出GroupDefinitionException异常。
定义了次序的组不应该直接继承其它组(即持有组序列的接口不应该有超接口)
定义了次序的组不应该直接用在约束声明中。
为了定义一个组为序列,接口必须用注解@GroupSequence标注
@Target({ TYPE })
@Retention(RUNTIME)
public @interface GroupSequence {
Class<?>[] value();
}
2.4.3 为类重新定义默认组
重新定义类的默认组,在类上使用@GroupSequence注解。
定义在类A上的序列必须包含组A(在类上的默认注解必须是序列定义的一部分)。当@GroupSequence为类A定义Default组,但是不包含组A,当类验证时或者请求元数据是会抛出GroupDefinitionException异常。
2.4.4 隐式分组
接口Z上承载的每个约束以及默认组的一部分(隐式或显式)都属于组Z
2.4.5 正式组定义
对于每个类X
- 对于X的每个超类Y,Y组包含Y的组Y的所有约束
- 组X包含以下约束
组X是用于重新定义类上默认组的序列的组
- 类X声明的每个约束都没有声明组或显式声明组默认值,所有都是Default
-
由X实现的任何接口声明的每个约束,且未注释@GroupSequence不显式声明组或显式声明组默认值,X的接口上承载的所有默认约束被X继承。将忽略标记为@GroupSequence的接口
-
如果X有一个直接超类Y,则组Y中的每个约束,X的超类上承载的所有默认约束,由类层次结构继承
-
如果X没有@GroupSequence注释,则组默认值包含以下约束
此规则定义在验证X上的默认值时计算哪些约束
- 组X中的每个约束
- 如果X有一个直接超类Y,则Y中默认组的每个约束
如果Y重新定义组默认值,则此规则是必需的
-
如果X有@GroupSequence注释,则组默认值包含属于每个由@GroupSequence注释声明的组,@GroupSequence注释必须声明组X
-
对于每个接口Z,组Z包含以下约束
-
接口Z声明的每个约束,这些约束没有显式声明组或组默认值显式,位于接口Z上的所有默认约束:该规则正式定义了每个接口的隐式分组
-
由z的任何没有注释@GroupSequence的超级接口声明的每个约束(不显式声明组),Z的接口上承载的所有默认约束:组可以被继承
-
类X声明的每个约束,它显式声明了组Z,由X承载并标记了的每个约束属于组Z
-
由X实现的任何接口声明的每个约束,且未注释@GroupSequence显式声明组Z,由X承载并标记了的每个约束属于组Z
-
如果X有一个直接超类Y,则Y的Z组中的每个约束,由X的任何超类承载并标记了的每个约束为属于组Z
-
对于每个注解了@GroupSequence的接口z,组z包含了属于注解@GroupSequence声明的每个组的每个约束。
2.5 验证过程
验证指定组,应用于指定bean实例的验证过程会执行如下的约束验证:
- 所有可到达的字段,执行符合组的字段级别的验证
- 所有可到达的getter要,执行所有指定符合组的getter级别的验证。
- 执行所有匹配目标组的类级别的验证。
- 对于所有可到达的以及级联的关系,执行所有级联的验证。
2.5.1 可遍历的属性
3、Validation API
4、元数据请求API
5、内置约束定义
@Null | |
@NotNull | |
@AssertTrue | |
@AssertFalse | |
@Min | |
@Max | |
@DecimalMin | |
@DecimalMax | |
@Size | |
@Digits | |
@Past | |
@Future | |
@Pattern |
参考资料: