任何获得Matrix授权的网站,转载请保留以下作者信息和链接:
作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
关键字:Hibernate Validator
在前一篇文章 < Hibernate Validator 简介 > http://www.matrix.org.cn/resource/article/44/44153_Hibernate%20Validator%20.html中,我们看到了Hibernate Validator的使用方法,和自定义验证Annotation的实现以及错误消息的国际化等常见问题.
在使用如此优雅的属性验证框架的同时,你是否想了解她的细节呢?她究竟是怎么实现的呢? 那么现在就跟随我来探探她的内核吧!
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<A
extends
Annotation> {
/**
* 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<T>
implements
Serializable {
private static
Log log = LogFactory.getLog( ClassValidator.
class
);
private static final
InvalidValue[] EMPTY_INVALID_VALUE_ARRAY =
new
InvalidValue[]{};
private final
Class<T> beanClass;
private transient
ResourceBundle messageBundle;
private transient boolean
defaultResourceBundle;
private final transient
Map<Class, ClassValidator> childClassValidators;
private transient
List<Validator> beanValidators;
private transient
List<Validator> memberValidators;
private transient
List<Member> memberGetters;
private transient
Map<Validator, String> messages;
private transient
List<Member> childGetters;
private static final
String DEFAULT_VALIDATOR_MESSAGE =
"org.hibernate.validator.resources.DefaultValidatorMessages"
;
/**
* create the validator engine for this bean type
*/
public
ClassValidator(Class<T> 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<T> beanClass, ResourceBundle resourceBundle) {
this
( beanClass, resourceBundle,
new
HashMap<Class, ClassValidator>() );
}
protected
ClassValidator(
Class<T> beanClass, ResourceBundle resourceBundle, Map<Class, ClassValidator> 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<T> beanClass, Map<Class, ClassValidator> childClassValidators,
ResourceBundle resourceBundle
) {
beanValidators =
new
ArrayList<Validator>();
// 保存类级别的验证约束实现类
memberValidators =
new
ArrayList<Validator>();
// 保存方法级别的验证约束实现类
memberGetters =
new
ArrayList<Member>();
// 保存类的成员(字段or方法)和构造函数方法的标识信息
messages =
new
HashMap<Validator, String>();
// 利用Map保存与每个Validator相对应的验证消息
childGetters =
new
ArrayList<Member>();
// 保存子类的成员(字段or方法)和构造函数方法的标识信息
childClassValidators.put( beanClass,
this
);
//map Map<Class, ClassValidator> 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<Class> classes =
new
HashSet<Class>();
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<Class> 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<Object> 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<InvalidValue> results =
new
ArrayList<InvalidValue>();
for
(
int
i =
0
; i < beanValidators.size() ; i++ ) {
// 验证类级别的约束
Validator validator = beanValidators.get( i );
if
( !validator.isValid( bean ) ) {
//调用isValid方法,如果没有通过则添加到list<InvalidValue>中
//如果是自定义约束则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<InvalidValue>中
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<InvalidValue> results =
new
ArrayList<InvalidValue>();
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<InvalidValue> results =
new
ArrayList<InvalidValue>();
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<Class, ClassValidator>(), rb );
}
}
还记得我们在验证时候所写的代码吗:
ClassValidator<Person> classValidator =
new
ClassValidator<Person> (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 论坛开了一讨论贴 请大家走过路过都看看:http://www.matrix.org.cn/thread.shtml?topicId=36657&forumId=23 让我们更高效的使用 Validator.