JSR 303 – Bean Validation
JSR 303是JAVA EE 6中的一项子规范,Bean Validation 为 JavaBean 验证定义了相应的元数据模型和 API。缺省的元数据是 Java Annotations,通过使用 XML 可以对Java注解信息进行覆盖和扩展;
例如: @NotNull, @Max, @ZipCode, 就可以确保数据模型(JavaBean)的正确性;
Constraint
constraint在JSR的规范上是这样说的:A constraint on a JavaBean is expressed through one or more annotations. An annotation is considered a constraint definition if its retention policy contains RUNTIMEand if the annotation itself is annotated withjavax.validation.Constraint
大概含义是:使用Constraint来使一个或更多个annotaion起作用
其定义如下:
@Documented
@Target({ ANNOTATION_TYPE })
@Retention(RUNTIME)
public @interface Constraint {
/**
* {@link ConstraintValidator} classes must reference distinct target types
* for a given {@link ValidationTarget}
* If two {@code ConstraintValidator}s refer to the same type,
* an exception will occur.
*
* At most one {@code ConstraintValidator} targeting the array of parameters of
* methods or constructors (aka cross-parameter) is accepted. If two or more
* are present, an exception will occur.
*
* @return array of (@code ConstraintValidator} classes implementing the constraint
*/
Class extends ConstraintValidator, ?>>[] validatedBy();
}
使用方法:
通过validatedBy指定校验器的class,Validation API的实现会自动加载你所指定的校验器,如下:
@Constraint(validatedBy = OrderNumberValidator.class)
package com.acme.constraint;
/**
* Mark a String as representing a well formed order number
*/
@Documented
*@Constraint(validatedBy = OrderNumberValidator.class)*
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RUNTIME)
public @interface OrderNumber {
String message() default "{com.acme.constraint.OrderNumber.message}";
Class>[] groups() default {};
Class extends Payload>[] payload() default {};
}
估计有人会有疑问,为什么自带的API都没有指定Validator,这个是因为如果是有官方定义的Api,在相应的Api实现上已经把指定的Validator加进去,例如:
Hibernate-validator是Validator Api实现,在ConstraintHelper的有如下代码:
public ConstraintHelper() {
Map, List extends Class>>> tmpConstraints = newHashMap();
putConstraint( tmpConstraints, AssertFalse.class, AssertFalseValidator.class );
putConstraint( tmpConstraints, AssertTrue.class, AssertTrueValidator.class );
putConstraint( tmpConstraints, CNPJ.class, CNPJValidator.class );
....省略部分代码
putConstraint( tmpConstraints, URL.class, URLValidator.class );
this.builtinConstraints = Collections.unmodifiableMap( tmpConstraints );
}
目前已有的Validator
Validator的官方实现Hibernate新增的Validator
如何使用:
写代码引入校验
Validator validator = Validation.byProvider( HibernateValidator.class )
.configure()
.failFast( true )
.buildValidatorFactory()
.getValidator();
Set> constraintViolations = validator.validate( anInstance );
在Spring中可以配置如下:
Validatior Api和Hibernate-Validator的关系
用过SPI来扩展实现,在Validator中
private static class GetValidationProviderListAction implements PrivilegedAction>> {
private static final WeakHashMap>>> providersPerClassloader =
new WeakHashMap>>>();
public static List> getValidationProviderList() {
final GetValidationProviderListAction action = new GetValidationProviderListAction();
if ( System.getSecurityManager() != null ) {
return AccessController.doPrivileged( action );
}
else {
return action.run();
}
}
public List> run() {
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
List> validationProviderList = loadProviders( classloader );
return validationProviderList;
}
private List> loadProviders(ClassLoader classloader) {
ServiceLoader loader = ServiceLoader.load( ValidationProvider.class, classloader );
Iterator providerIterator = loader.iterator();
List> validationProviderList = new ArrayList>();
while ( providerIterator.hasNext() ) {
try {
validationProviderList.add( providerIterator.next() );
}
catch ( ServiceConfigurationError e ) {
}
}
return validationProviderList;
}
}
下一章将对如何使用Annotation和Xml两种方式来实现对Java Bean的校验