`
icess
  • 浏览: 248113 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

解析 Hibernate Validator

阅读更多

任何获得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

分享到:
评论

相关推荐

    HibernateValidatorJSR303的参考实现使用指南.pdf

    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...

    基于SpringMVC+Hibernate4的考勤管理系统+.zip

    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 XML Validator for Eclipse:Eclipse 插件,用于根据 @Entity 文件验证 Hibernate ORM 文件。-开源

    默认情况下,Hibernate .ORM 文件仅在服务器启动时解析。 仅仅因为您的 orm xml 中的一个简单错误而导致服务器启动失败是一个小刺激。 该项目旨在为 Eclipse 创建一个插件,该插件将监视所有带有 @Entity 注释的 ...

    E-BookStore:这是电子商店在线图书市场的服务器端程序,这是在母亲组织的大学EE培训期间的实用Java Web应用程序

    Hibernate Validator用于数据验证检查 用于Lambda 用于数据库连接池的Tomcat JDBC Pool Fast Json(由阿里巴巴制造)用于Json解析器 Gson(由Google制造)用于Json-Object转换 jQuery和Ajax用于前端和数据传输 ...

    基于Dubbo实现的SOA分布式(没有实现分布式事务)-SpringBoot整合各种组件的JavaWeb脚手架+源代码+文档

    - Hibernate Validator - Redis Cluster - MySQL主从复制,读写分离 - Spring Async - Spring Cache - Swagger - Spring Test - MockMvc - HTTPS - Spring DevTools - Spring Actuator - Logback+Slf4j多环境日志 - ...

    开源框架 Spring Gossip

    第一个 Hibernate 程式 SessionFactory 注入 HibernateTemplate Hibernate 编程交易管理 Hibernate 宣告式交易管理 &lt;br&gt; Web 层 Spring 提供了 MVC Web 框架,您可以善用 IoC 容器...

    Spring 2.0 开发参考手册

    5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...

    spring chm文档

    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、...

    java面试宝典

    203、编程用JAVA解析XML的方式. 49 204、EJB2.0有哪些内容?分别用在什么场合? EJB2.0和EJB1.1的区别? 51 205、EJB与JAVA BEAN的区别? 51 206、EJB的基本架构 51 207、MVC的各个部分都有那些技术来实现?如何实现? 52...

    Spring中文帮助文档

    5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...

    Spring API

    5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 6. 使用Spring进行面向切面编程(AOP...

    Spring-Reference_zh_CN(Spring中文参考手册)

    5.2. 使用Spring的Validator接口进行校验 5.3. 从错误代码到错误信息 5.4. Bean处理和BeanWrapper 5.4.1. 设置和获取属性值以及嵌套属性 5.4.2. 内建的PropertyEditor实现 5.4.2.1. 注册用户自定义的PropertyEditor ...

    DWR.xml配置文件说明书(含源码)

    import org.apache.commons.validator.EmailValidator; return EmailValidator.getInstance(); ... 4 Signatures in dwr.xml Signatures部分用于配置Collections中装载对象元素的类型.举个例子来说:下面的...

Global site tag (gtag.js) - Google Analytics