- 浏览: 248113 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
tanglingshuai:
liulehua 写道根本原因是:没有把该对象对应的主键保存到 ...
关于: org.hibernate.StaleStateException: Batch update -
javeye:
转载了你的文章http://javeye.iteye.com/ ...
关于在tomcat下配置 error-page 500错误不能在IE下转发页面的问题 -
imlsq:
嘿嘿, 使用SEAM 7-8个月时间了还是放弃使用SEAM的想 ...
发现一个Seam做的企业应用,blackberry的在线商店 -
yuanliyin:
我也在用,唯一不爽的就是性能!
发现一个Seam做的企业应用,blackberry的在线商店 -
perfect:
假的 ,大家不要上当 ,根本不能用
HttpWatch 6.1.41 许可文件
任何获得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 );
}
#fff
发表评论
-
学习使用Java DataBase (Derby) -- 嵌入式数据库
2006-04-13 21:19 1721学习使用Java DataBas ... -
在derby(Java DB) 中操作 clob 和 blob
2006-04-14 15:23 1444在前面一篇文章中, ... -
利用swing开源组件和netbeans快速构建豪华swing界面
2006-04-15 13:41 1386利用swing开源组件和netbeans快速构建豪华s ... -
Java Pet Store 开始全面使用 Web 2.0 技术
2006-05-16 21:58 1012Java Pet Store 开 ... -
Hibernate Validator 简介
2006-05-17 10:35 1224Hibernate Validator 简介 ... -
Google发布AJAX开发工具 Google Web Toolkit
2006-05-17 21:17 847Google Web Toolkit - Build ... -
Spring in Action 笔记(I)
2006-05-22 14:13 839By : icess ,我的部落格 http:// ... -
Spring in Action 笔记(II)
2006-05-25 00:04 1106... -
Spring in Action 笔记(III) -- 在Spring下的Hibernate数据操作
2006-05-27 11:01 794Spring in A ... -
Spring in Action 笔记 (IV) -- i18n问题和自定义属性编辑器
2006-05-29 11:24 936Spring in Action 笔记 (IV) -- i18 ... -
Breezy简介 -- 快速开发Swing程序!
2006-06-04 22:33 1374Breezy简介 -- 快速开发Swing程序! ... -
最新消息 ,开源嵌入式数据库 Derby(JavaDB) 绑定在JDK 1.6中.
2006-06-18 18:48 1661如下:Source: Fran ... -
callisto(Eclipse 3.2) 迟到了 ?
2006-06-30 23:04 738在今天早些时候访问 callisto 的主页(http://w ... -
Callisto 终于可以下载了.
2006-07-01 04:47 729Callisto 终于可以下载了. Eclipse 3.2 ... -
最近想研究一下DWR 收集一些从入门到精通的系列资料
2006-07-13 15:55 909最近想研究一下DWR 收集一些从入门到精通的系列资料, 以备将 ... -
decode javascript.encode using java
2006-08-01 13:18 1502在前面一篇文章(http://www.hexiao.cn/bl ... -
Wicket 入门示例 :Hello World.
2006-08-05 10:38 1178Wicket http://wicketframework.o ... -
Wicket 教程2: 如何使用Label,MultiLineLabel,Border,BoxBorder
2006-08-07 15:29 1349上次介绍了一个wicket的一个HelloWorld入门示例, ... -
Wicket 教程3:使用 PageView 来调试页面
2006-08-08 09:22 1526使用 PageView 来调试页面.Wicket中提供了一个P ... -
Wicket 教程4:如何使用 Include,Panel,Fragment,Link
2006-08-08 09:25 2028Wicket 教程4:如何使用 ...
相关推荐
8. Hibernate Validator Specifics 8.1. Public API 8.2. Fail fast mode 8.3. Method validation 8.3.1. Defining method-level constraints 8.3.2. Evaluating method-level constraints 8.3.3. Retrieving method...
hibernate-validator-annotation-processor-5.1.3.Final.jar jandex-1.1.0.Final.jar javassist-3.18.1-GA.jar jboss-logging-3.1.3.GA.jar jboss-logging-annotations-1.2.0.Beta1.jar jboss-transaction-api_1.2_...
默认情况下,Hibernate .ORM 文件仅在服务器启动时解析。 仅仅因为您的 orm xml 中的一个简单错误而导致服务器启动失败是一个小刺激。 该项目旨在为 Eclipse 创建一个插件,该插件将监视所有带有 @Entity 注释的 ...
Hibernate Validator用于数据验证检查 用于Lambda 用于数据库连接池的Tomcat JDBC Pool Fast Json(由阿里巴巴制造)用于Json解析器 Gson(由Google制造)用于Json-Object转换 jQuery和Ajax用于前端和数据传输 ...
- Hibernate Validator - Redis Cluster - MySQL主从复制,读写分离 - Spring Async - Spring Cache - Swagger - Spring Test - MockMvc - HTTPS - Spring DevTools - Spring Actuator - Logback+Slf4j多环境日志 - ...
第一个 Hibernate 程式 SessionFactory 注入 HibernateTemplate Hibernate 编程交易管理 Hibernate 宣告式交易管理 <br> Web 层 Spring 提供了 MVC Web 框架,您可以善用 IoC 容器...
5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...
5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...
94、元素有一个cascade属性,如果希望Hibernate级联保存集合中的对象,casecade属性应该取什么值?(单选)(D) 22 95、以下哪些属于Session的方法?(A,B,C,D,F) 22 96、Hibernate工作原理及为什么要用? 22 97、...
203、编程用JAVA解析XML的方式. 49 204、EJB2.0有哪些内容?分别用在什么场合? EJB2.0和EJB1.1的区别? 51 205、EJB与JAVA BEAN的区别? 51 206、EJB的基本架构 51 207、MVC的各个部分都有那些技术来实现?如何实现? 52...
5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...
5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...
5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 5.4.2.1. 注册用户自定义的PropertyEditor ...
import org.apache.commons.validator.EmailValidator; return EmailValidator.getInstance(); ... 4 Signatures in dwr.xml Signatures部分用于配置Collections中装载对象元素的类型.举个例子来说:下面的...