扩展内建约束集是极其方便的。任何约束都包括两部分:约束
描述符
(注解)
和约束
验证器
(实现类)。下面是一个简单的用户定义描述符:
@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "has incorrect capitalization";
}
type
参数描述属性应该如何被大写。这是一个完全依赖于注解业务(逻辑)的用户
参数。
message
是用于描述约束违规的默认字符串,它是强制要求的。你可以采取硬编码的方式,
或者通过Java ResourceBundle机制将message的部分/全部内容提取至外部文件。一旦发现message中{parameter}字符串,
就会在{parameter}这个位置注入相应的参数值(在我们的例子里Capitalization is not {type}会生成 Capitalization is not FIRST),
可以将message对应的整个字符串提取至外部文件ValidatorMessages.properties,这也是一种良好实践。
见
Error messages
。
@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "{validator.capitalized}";
#in ValidatorMessages.properties
validator.capitalized=Capitalization is not {type}
如你所见{}符号是递归的。
为了将一个描述符连接到它的验证器实现,我们使用
@ValidatorClass
元注解。验证器类参数必须指定一个实现了
Validator<ConstraintAnnotation>
的类。
我们现在要实现验证器(也就是实现规则检查)。一个验证器实现能检查一个属性的值
(实现
PropertyConstraint
),并且/或者可以修改hibernate映射元数据
(实现
PersistentClassConstraint
),籍此表示数据库级的约束。
public class CapitalizedValidator
implements Validator<Capitalized>, PropertyConstraint {
private CapitalizeType type;
//part of the Validator<Annotation> contract,
//allows to get and use the annotation values
public void initialize(Capitalized parameters) {
type = parameters.type();
//part of the property constraint contract
public boolean isValid(Object value) {
if (value==null) return true;
if ( !(value instanceof String) ) return false;
String string = (String) value;
if (type == CapitalizeType.ALL) {
return string.equals( string.toUpperCase() );
else {
String first = string.substring(0,1);
return first.equals( first.toUpperCase();
}
如果违反约束,
isValid()
方法将返回false。更多例子请参考内建验证器实现。
至此我们只看到属性级的验证,你还可以写一个Bean级别的验证注解。Bean自身会被传递给验证器,
而不是bean的属性实例。只要对bean自身进行注解即可激活验证检查。在单元测试套件中还可以找到一个小例子。