站内搜索: 请输入搜索关键词

当前页面: 开发资料首页J2EE 专题解析 Hibernate Validator

解析 Hibernate Validator

摘要: Hibernate Validator 可以是一个独立的验证框架, 所以看完这篇分析 你可以把她独立出来作为你的个人验证框架来使用了 ^_^(如果你有兴趣和时间的话). Hibernate Validator 框架里面有两个主要的类: ClassValidator 和InvalidValue 还有一个接口Validator,在这三个主要的构件?最主要的就只有一个 那就是ClassValidator.另外两个是很好理解的..
在前一篇文章 < Hibernate Validator 简介 > http://www.matrix.org.cn/resource/article/44/44153_Hibernate%20Validator%20.html中,我们看到了Hibernate Validator的使用方法,和自定义验证Annotation的实现以及错误消息的国际化等常见问题.

任何获得Matrix授权的网站,转载请保留以下作者信息和链接:
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
关键字:Hibernate Validator

在使用如此优雅的属性验证框架的同时,你是否想了解她的细节呢?她究竟是怎么实现的呢? 那么现在就跟随我来探探她的内核吧!

Hibernate Validator 可以是一个独立的验证框架, 所以看完这篇分析 你可以把她独立出来作为你的个人验证框架来使用了 ^_^(如果你有兴趣和时间的话). Hibernate Validator 框架里面有两个主要的类: ClassValidator 和InvalidValue 还有一个接口Validator,在这三个主要的构件中 最主要的就只有一个 那就是ClassValidator.另外两个是很好理解的..

现在就让我们开始吧. 遵循由浅入深的习惯 我们先看看 Validator 接口吧. 其代码如下:

import java.lang.annotation.Annotation;

/**
* A constraint validator for a particular annotation
*
* @author Gavin King
*/
public interface Validator {
/**
* does the object/element pass the constraints
*/
public boolean isValid(Object value);

/**
* Take the annotations values
* @param parameters
*/
public void initialize(A parameters);
}


Validator接口就是我们自定义约束的实现类要继承的接口,该接口在< Hibernate Validator 简介 > http://www.matrix.org.cn/resource/article/44/44153_Hibernate%20Validator%20.html中已经讨论过了,请参考.

InvalidValue 类 大家看名字就应该可以猜到她的作用了吧. 她就是代表一个没有通过验证的错误实例.该类定义了一些方法,通过这些方法你可以取得与该Validator Annotation 有关的一些参数,如:她所注释的属性的值,错误消息等等. 该类的源代码如下:

import java.io.Serializable;

/**
* A single violation of a class level or method level constraint.
*
* @author Gavin King
*/
public class InvalidValue implements Serializable {
private final String message;
private final Object value;
private final String propertyName;
private final Class beanClass;
private final Object bean;
private Object rootBean;

public Object getRootBean() {
return rootBean;
}

public String getPropertyPath() {
return propertyPath;
}

private String propertyPath;

public InvalidValue(String message, Class beanClass, String propertyName, Object value, Object bean) {
this.message = message;
this.value = value;
this.beanClass = beanClass;
this.propertyName = propertyName;
this.bean = bean;
this.rootBean = bean;
this.propertyPath = propertyName;
}

public void addParentBean(Object parentBean, String propertyName) {
this.rootBean = parentBean;
this.propertyPath = propertyName + "." + this.propertyPath;
}

public Class getBeanClass() {
return beanClass;
}

public String getMessage() {
return message;
}

public String getPropertyName() {
return propertyName;
}

public Object getValue() {
return value;
}

public Object getBean() {
return bean;
}

public String toString() {
return propertyName + ' ' + message;
}

}


然后,就让我们看看最主要的类吧:ClassValidator . 该类代码有400余行,我都做了详细的注释如下:

import 该部分省略了;


/**
* Engine that take a bean and check every expressed annotation restrictions
*
* @author Gavin King
*/
public class ClassValidator implements Serializable {
private static Log log = LogFactory.getLog( ClassValidator.class );
private static final InvalidValue[] EMPTY_INVALID_VALUE_ARRAY = new InvalidValue[]{};
private final Class beanClass;
private transient ResourceBundle messageBundle;
private transient boolean defaultResourceBundle;

private final transient Map childClassValidators;
private transient List beanValidators;
private transient List memberValidators;
private transient List memberGetters;
private transient Map messages;
private transient List childGetters;
private static final String DEFAULT_VALIDATOR_MESSAGE = "org.hibernate.validator.resources.DefaultValidatorMessages";


/**
* create the validator engine for this bean type
*/
public ClassValidator(Class beanClass) {
this( beanClass, null );
}

/**
* create the validator engine for a particular bean class, using a resource bundle
* for message rendering on violation
*/
public ClassValidator(Class beanClass, ResourceBundle resourceBundle) {
this( beanClass, resourceBundle, new HashMap() );
}

protected ClassValidator(
Class beanClass, ResourceBundle resourceBundle, Map childClassValidators
) {
this.beanClass = beanClass;
this.messageBundle = resourceBundle == null ?
getDefaultResourceBundle() :
resourceBundle;
this.childClassValidators = childClassValidators;
initValidator( beanClass, childClassValidators, this.messageBundle ); //重要的是该初始化函数
}

private ResourceBundle getDefaultResourceBundle() {
ResourceBundle rb;
try {
rb = ResourceBundle.getBundle( "ValidatorMessages" );
}
catch( MissingResourceException e) {
//the user did not override the default ValidatorMessages
log.debug( "ResourceBundle ValidatorMessages not found. Delegate to " + DEFAULT_VALIDATOR_MESSAGE);
rb = ResourceBundle.getBundle( DEFAULT_VALIDATOR_MESSAGE );
}
defaultResourceBundle = true;
return rb;
}

private void initValidator(
Class beanClass, Map childClassValidators,
ResourceBundle resourceBundle
) {
beanValidators = new ArrayList(); // 保存类级别的验证约束实现类
memberValidators = new ArrayList(); // 保存方法级别的验证约束实现类
memberGetters = new ArrayList();// 保存类的成员(字段or方法)和构造函数方法的标识信息
messages = new HashMap(); // 利用Map保存与每个Validator相对应的验证消息
childGetters = new ArrayList();// 保存子类的成员(字段or方法)和构造函数方法的标识信息

childClassValidators.put( beanClass, this ); //map Map childClassValidators;
Annotation[] classAnnotations = beanClass.getAnnotations();
for ( int i = 0; i < classAnnotations.length ; i++ ) {
Annotation classAnnotation = classAnnotations[i];
Validator beanValidator = createValidator( classAnnotation );//根据Annotation来得到Validator,参考对该函数的解释
if ( beanValidator != null ) beanValidators.add( beanValidator );//保存该Validator
}
//build the class hierarchy to look for members in
Collection classes = new HashSet();
addSuperClassesAndInterfaces( beanClass, classes );//把beanClass的所有超类和实现的接口添加的集合classes中

//Check on all selected classes
for ( Class currClass : classes ) {
Method[] methods = currClass.getDeclaredMethods();// 扫描Method上面的注释
for ( int i = 0; i < methods.length ; i++ ) {
Method method = methods[i];
createMemberValidator( method ); // 创建方法上的约束实现类(Validator), 参考对该函数的解释
Class clazz = method.getReturnType();// 得到该方法的返回类型
createChildValidator( resourceBundle, method, clazz );// 创建子类的Validator
}

Field[] fields = currClass.getDeclaredFields(); // 扫描Field上面的注释, 下面和上面Method的实现一样
for ( int i = 0; i < fields.length ; i++ ) {
Field field = fields[i];
createMemberValidator( field );
Class clazz = field.getType();
createChildValidator( resourceBundle, field, clazz );
}
}
}

private void addSuperClassesAndInterfaces(Class clazz, Collection classes) {
for ( Class currClass = clazz; currClass != null ; currClass = currClass.getSuperclass() ) {
if ( ! classes.add( currClass ) ) return;
Class[] interfaces = currClass.getInterfaces();
for (Class interf : interfaces) {
addSuperClassesAndInterfaces( interf, classes );
}
}
}

/**
* 创建内嵌类的Validator. 如果该内嵌类被Valid Annotation 注释的话则
* 创建另外一个ClassValidator
* @param resourceBundle
* @param member
* @param clazz
*/
private void createChildValidator(ResourceBundle resourceBundle, Member member, Class clazz) {
if ( ( (AnnotatedElement) member ).isAnnotationPresent( Valid.class ) ) {
setAccessible( member );
childGetters.add( member );
if ( !childClassValidators.containsKey( clazz ) ) {
new ClassValidator( clazz, resourceBundle, childClassValidators );
}
}
}

/**
* 利用传入的Method(实现了AnnotatedElement, GenericDeclaration, Member接口)
* 得到 方法上的Annotations 然后利用私有方法createValidator(Annotation a)来创建
* 每一个Annotation 的实现类 Validator 并保存Validator和member
* @param member
*/
private void createMemberValidator(Member member) {
Annotation[] memberAnnotations = ( (AnnotatedElement) member ).getAnnotations();
for ( int j = 0; j < memberAnnotations.length ; j++ ) {
Annotation methodAnnotation = memberAnnotations[j];
Validator propertyValidator = createValidator( methodAnnotation );
if ( propertyValidator != null ) {
memberValidators.add( propertyValidator );
setAccessible( member ); // 设置访问属性
memberGetters.add( member );
}
}
}

private static void setAccessible(Member member) {
if ( !Modifier.isPublic( member.getModifiers() ) ) {
( (AccessibleObject) member ).setAccessible( true );
}
}

/**
* 该方法产生了该Annotation的约束实现类 并初始化该类对应的消息
*/
private Validator createValidator(Annotation annotation) {
try {
//得到ValidatorClass Annotation
ValidatorClass validatorClass = annotation.annotationType().getAnnotation( ValidatorClass.class );
if ( validatorClass == null ) {
return null;
}
// 然后 利用ValidatorClass Annotation 来得到里面的值(即实现该注释的Class),
//再利用Class 构造一个instance
Validator beanValidator = validatorClass.value().newInstance();
beanValidator.initialize( annotation ); // 初始化Annotation中的参数(注意:在自定义约束中该方法有你来实现)
String messageTemplate = (String) annotation.getClass()
.getMethod( "message", (Class[]) null )
.invoke( annotation ); // 取得 constraint descriptor 中的message 的值
String message = replace( messageTemplate, annotation ); // 初始化取得的模板消息 请参考 replace函数
messages.put( beanValidator, message ); // 把message 放在map中,以便使用
return beanValidator; // 返回 产生的Validator
}
catch (Exception e) {
throw new IllegalArgumentException( "could not instantiate ClassValidator", e );
}
}

public boolean hasValidationRules() {
return beanValidators.size() != 0 || memberValidators.size() != 0;
}

/**
* apply constraints on a bean instance and return all the failures.
*/
public InvalidValue[] getInvalidValues(T bean) {
return this.getInvalidValues( bean, new IdentitySet() );
}

/**
* apply constraints on a bean instance and return all the failures.
*/
protected InvalidValue[] getInvalidValues(T bean, Set circularityState) {
if ( circularityState.contains( bean ) ) { // 该if else 是和Hibernate Core由关的,
return EMPTY_INVALID_VALUE_ARRAY; //Avoid circularity
}
else {
circularityState.add( bean );
}

if ( !beanClass.isInstance( bean ) ) { // 如果beanClass不是该bean的实例,则抛出异常
throw new IllegalArgumentException( "not an instance of: " + bean.getClass() );
}

List results = new ArrayList();

for ( int i = 0; i < beanValidators.size() ; i++ ) { // 验证类级别的约束
Validator validator = beanValidators.get( i );
if ( !validator.isValid( bean ) ) { //调用isValid方法,如果没有通过则添加到list
//如果是自定义约束则isValid方法 由你来实现
results.add( new InvalidValue( messages.get( validator ), beanClass, null, bean, bean ) );
}
}

for ( int i = 0; i < memberValidators.size() ; i++ ) {//验证方法级别的约束
Member getter = memberGetters.get( i );
if ( Hibernate.isPropertyInitialized(bean, getter.getName() ) ) {// ? 检查该属性是否已初始化
Object value = getMemberValue( bean, getter );//利用反射 取得该属性的值
Validator validator = memberValidators.get( i ); //取得该约束的验证实现类
if ( !validator.isValid( value ) ) {//调用isValid方法,如果没有通过则添加到list
String propertyName = getPropertyName( getter );
results.add( new InvalidValue( messages.get( validator ), beanClass, propertyName, value, bean ) );
}
}
}

for ( int i = 0; i < childGetters.size() ; i++ ) {// 处理子类类
Member getter = childGetters.get( i );
if ( Hibernate.isPropertyInitialized(bean, getter.getName() ) ) { //检查该属性是否已初始化
Object value = getMemberValue( bean, getter );
if ( value != null && Hibernate.isInitialized( value ) ) {
String propertyName = getPropertyName( getter );
InvalidValue[] invalidValues = getClassValidator( value )
.getInvalidValues( value, circularityState );// 通过参数value 得到 Class, 然后由Class作为key //在childClassValidators map中得到其ClassValidator
//如果不存在 则创建新的 ,然后再调用ClassValidator的getInvalidValues方法
// 注意在调用getInvalidValues方法时 用到了circularityState 参数, 当调用循环一周时 返回(递归结束)
for ( InvalidValue invalidValue : invalidValues ) {
invalidValue.addParentBean( bean, propertyName );
results.add( invalidValue ); //添加的结果中
}
}
}
}

return results.toArray( new InvalidValue[results.size()] ); //返回InvalidValue数组
}

/**
* 通过参数value 得到 Class, 然后由Class作为key 在childClassValidators map中得到其ClassValidator
* 如果不存在 则创建新的 然后返回
* @param value
* @return
*/
private ClassValidator getClassValidator(Object value) {
Class clazz = value.getClass();
ClassValidator validator = childClassValidators.get( clazz );
if ( validator == null ) { //handles polymorphism
validator = new ClassValidator( clazz );
}
return validator;
}

/**
* Apply constraints of a particular property on a bean instance and return all the failures.
* Note this is not recursive.
* 验证单个属性的约束.
*/
//TODO should it be recursive ?
public InvalidValue[] getInvalidValues(T bean, String propertyName) {
List results = new ArrayList();

for ( int i = 0; i < memberValidators.size() ; i++ ) {
Member getter = memberGetters.get( i );
if ( getPropertyName( getter ).equals( propertyName ) ) {// 验证该属性的约束
Object value = getMemberValue( bean, getter );
Validator validator = memberValidators.get( i );
if ( !validator.isValid( value ) ) {
results.add( new InvalidValue( messages.get( validator ), beanClass, propertyName, value, bean ) );
}
}
}

return results.toArray( new InvalidValue[results.size()] );
}

/**
* Apply constraints of a particular property value of a bean type and return all the failures.
* The InvalidValue objects returns return null for InvalidValue#getBean() and InvalidValue#getRootBean()
* Note this is not recursive.
* 验证 value 是否满足当前属性的约束.
*/
//TODO should it be recursive?
public InvalidValue[] getPotentialInvalidValues(String propertyName, Object value) {
List results = new ArrayList();

for ( int i = 0; i < memberValidators.size() ; i++ ) {
Member getter = memberGetters.get( i );
if ( getPropertyName( getter ).equals( propertyName ) ) {
Validator validator = memberValidators.get( i );
if ( !validator.isValid( value ) ) {
results.add( new InvalidValue( messages.get( validator ), beanClass, propertyName, value, null ) );
}
}
}

return results.toArray( new InvalidValue[results.size()] );
}

private Object getMemberValue(T bean, Member getter) {
Object value;
try {
value = getValue( getter, bean );
}
catch (Exception e) {
throw new IllegalStateException( "Could not get property value", e );
}
return value;
}

private Object getValue(Member member, T bean) throws IllegalAccessException, InvocationTargetException {
if ( member instanceof Field ) {
return ( (Field) member ).get( bean );
}
else if ( member instanceof Method ) {
return ( (Method) member ).invoke( bean );
}
else {
throw new AssertionFailure( "Unexpected member: " + member.getClass().getName() );
}
}

public String getPropertyName(Member member) {
//Do no try to cache the result in a map, it's actually much slower (2.x time)
String propertyName;
if ( member instanceof Field ) {
propertyName = member.getName();
}
else if ( member instanceof Method ) {
propertyName = member.getName();
if ( propertyName.startsWith( "is" ) ) {
propertyName = Introspector.decapitalize( propertyName.substring( 2 ) );
}
else if ( propertyName.startsWith( "get" ) ) {
propertyName = Introspector.decapitalize( propertyName.substring( 3 ) );
}
//do nothing for non getter method, in case someone want to validate a PO Method
}
else {
throw new AssertionFailure( "Unexpected member: " + member.getClass().getName() );
}
return propertyName;
}

private String replace(String message, Annotation parameters) {
StringTokenizer tokens = new StringTokenizer( message, "{}", true );
StringBuilder buf = new StringBuilder( 30 );
boolean escaped = false;
while ( tokens.hasMoreTokens() ) {
String token = tokens.nextToken();
if ( "{".equals( token ) ) {
escaped = true;
}
else if ( "}".equals( token ) ) {
escaped = false;
}
else if ( !escaped ) {
buf.append( token );
}
else {
Method member;
try {
member = parameters.getClass().getMethod( token, (Class[]) null );
}
catch (NoSuchMethodException nsfme) {
member = null;
}
if ( member != null ) {
try {
buf.append( member.invoke( parameters ) );
}
catch (Exception e) {
throw new IllegalArgumentException( "could not render message", e );
}
}
else if ( messageBundle != null ) {
String string = messageBundle.getString( token );
if ( string != null ) buf.append( replace( string, parameters ) );
}
}
}
return buf.toString();
}

/**
* apply the registred constraints rules on the hibernate metadata (to be applied on DB schema...)
*该方法是与实体类绑定的 不推荐使用 有兴趣的读者可以自己研究一下
* @param persistentClass hibernate metadata
*/
public void apply(PersistentClass persistentClass) {
//源代码省略
}

/**
* 断言该bean 是否符合所有约束. 负责抛出异常
* @param bean
*/
public void assertValid(T bean) {
InvalidValue[] values = getInvalidValues( bean );
if ( values.length > 0 ) {
throw new InvalidStateException( values );
}
}

/**
* 该方法应该是序列化ResourceBundle的 为private方法 但并没有用到, 不知道为什么 可能以后会有用
* @param oos
* @throws IOException
*/
private void writeObject(ObjectOutputStream oos) throws IOException {
ResourceBundle rb = messageBundle;
if ( rb != null && ! ( rb instanceof Serializable ) ) {
messageBundle = null;
if ( ! defaultResourceBundle )
log.warn( "Serializing a ClassValidator with a not serializable ResourceBundle: ResourceBundle ignored" );
}
oos.defaultWriteObject();
oos.writeObject( messageBundle );
messageBundle = rb;
}

/**
* 该方法应该是读取序列化的ResourceBundle的 为private方法 但并没有用到,不知道为什么 可能以后会有用
* @param ois
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
ResourceBundle rb = (ResourceBundle) ois.readObject();
if (rb == null) rb = getDefaultResourceBundle();
initValidator( beanClass, new HashMap(), rb );
}
}

还记得我们在验证时候所写的代码吗:

 ClassValidator classValidator = new ClassValidator (Person.class);
InvalidValue[] validMessages = classValidator.getInvalidValues(p);


只调用了classValidator的getInvalidValues(p);方法 我们就得到了InvalidValue[] validMessages, 该方法做了什么事情呢? 有上面的注释看起来就轻松多了 ^_^.

首先:在你创建ClassValidator时, 会调用ClassValidator的构造方法 她一供有三个构造函数 :


有两个构造函数(一个传递要验证的类为参数,一个还要加上你自定义的ResourceBundle)来供我们使用, 还有一个protected 的构造函数. 在构造函数中都做了写什么呢?

第一: 把要验证的类保存起来,第二:决定使用的消息资源,如果你提供了自己的ResourceBundle 就使用自定义消息,否则使用默认的消息资源.第三: 根据java反射机制,利用Annotation初始化所有的验证约束类,然后验证是否满足验证条件.

下面我们来关注一下initValidator 方法,看看是如何初始化验证约束类的. 现在请仔细看看 initValidator 里面的注释.然后在继续往下看.^_^

通过上面的分析,可以看到在 initValidator函数中,初始化了你传入类的所有的约束Annotations 的相关的东东(如: 其约束验证实现类, 如果有内嵌的类,如果该类被Valid Annotation注释的话 也构造一个内嵌类的Validator 并初始化其相关的东东 如此递归执行下去).该函数执行完后,可以说构造了一个以你传入的类为跟的 约束注释树(自创的名词,不了解也没关系 ^_^),然后由此树来逐个验证没有个约束.此时已经具备验证约束的条件了.你只有调用classValidator.getInvalidValues(p)方法就可以验证类p 上的所有约束了.

GetInvalidValues()方法有做了什么呢, 现在你要再回到上面看看她的注释了 ^_^:

怎么样现在知道 GetInvalidValues 做了什么了吧.她就是取出 约束注释树中的每一个约束注释(分为 类注释, 方法注释, 属性注释 和内嵌类注释 (也就是类里面的类属性)),并验证相应的成员是否满足该约束注释的要求,也就是调用Validator的isValid() 方法.最后用不满足要求的 成员信息构造InvalidValue 数组 并返. ClassValidator 类我们基本上已经讲解完了,剩下的该Validatro里面的就是一些内建的约束Annotation和约束验证实现类了,这些看看前一篇文章就明白怎么回事了.到此 HibernateValidator 框架基本上分析完了. 通过分析该框架.让我看到了Annotation的一种高级用法的实现机制,和反射机制的巧妙应用,以及几个巧妙的设计模式(我就不在举例了 大家可以相互探讨一下). 你从中学到了什么呢?

对想把Hibernate Validator做成一个独立框架的几点说明:

1.去掉apply 函数.

2. 在getPropertyName 和 getMemberValue 中 如果得到的值为null 则抛出org.hibernate.AssertionFailure异常. 可以重写该异常,或者从Hibernate源代码中提取(建议重写).

3.用到了Hibernate.isPropertyInitialized(Object o,String name)方法 判断该类(o)的属性(name)是否以及加载的, 该函数的doc 注释为 Check if the property is initialized. If the named property does not exist or is not persistent, this method always returns true.可以替换为判断该属性(name)是否为null, null即代表没有赋初值(可能违反约束);否则验证该值是否违反约束.

4.里面还用到了org.hibernate.util.IdentitySet 一个set实现,可以自己实现或者从Hibernate中提取(推荐提取);

这样一个独立的Validation frameWork 就出来了. 不依赖任何第三方代码,完全可以作为你自己的验证框架在项目中使用.

资源:
PS: 关于在实体类上(持久化层)使用Validator是否有好处,
大家可以看看:http://www.hibernate.org.cn/viewtopic.php?t=18131

我也在Matrix Hibernate 论坛开了一讨论贴 请大家走过路过都看看:
我们更高效的使用 Validator:http://www.matrix.org.cn/thread.shtml?topicId=36657&forumId=23 让
↑返回目录
前一篇: 基于Servlet的Google Earth之旅
后一篇: 基于时间戳的缓存构架:最近的数据拥有最佳的性能