<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    posts - 78,  comments - 48,  trackbacks - 0

    摘要:

    在項(xiàng)目的業(yè)務(wù)屬性中,你是不是要經(jīng)常驗(yàn)證屬性的取值范圍呢. 想要了解比較優(yōu)美的解決方案嗎? 看看Hibernate Validator 是怎么做的吧.一見(jiàn)到她,相信你就會(huì)說(shuō): Oh God, 這就是我需要的.

    作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
    關(guān)鍵字:Hibernate Validator
                  
    用Annotations 給類或者類的屬性加上約束(constraint),在運(yùn)行期檢查屬性值是很優(yōu)雅的.Hibernate Validator就是這樣的一個(gè)框架.該框架是十分容易的(就像參考文檔中宣稱的那樣),幾乎沒(méi)有什么學(xué)習(xí)曲線,Validator 是一個(gè)驗(yàn)證框架 不需要和Hibernate的其他部分綁定就可以使用,只要在你的項(xiàng)目中添加Hibernate-annotations.jar庫(kù)就可以了.那么下面就讓我們看看怎么使用吧.

    Person.java 類
    /*
    * Created on 2006-1-12 Person.java
    * @author
    */
    package test.annotation.validator;

    import org.hibernate.validator.Length;
    import org.hibernate.validator.Min;
    import org.hibernate.validator.Valid;
     

    //@Serializability  //測(cè)試自定義約束
    public class Person {

      private String name;
      private int age;
      private Address address;
      
      public Person() {}
      
      @Valid //注意此處
      public Address getAddress() {
        return address;
      }
      public void setAddress(Address address) {
        this.address = address;
      }
      
      @Min(value = 1)
      public int getAge() {
        return age;
      }
      public void setAge(int age) {
        this.age = age;
      }
      
      @Length(min = 4)
      public String getName() {
        return name;
      }
      public void setName(String name) {
        this.name = name;
      }
    }


    Address.java 類
    /*
    * Created on 2006-1-12 Address.java
    * @author
    */
    package test.annotation.validator;

    import org.hibernate.validator.Length;
    import org.hibernate.validator.Max;
    import org.hibernate.validator.Min;

    public class Address {

      private String street;
      private int num;
      
      public Address() {}
      
      @Min(value = 1)
      @Max(value = 100)
      public int getNum() {
        return num;
      }
      public void setNum(int num) {
        this.num = num;
      }
      
      @Length(min = 3,max = 8)
      public String getStreet() {
        return street;
      }
      public void setStreet(String street) {
        this.street = street;
      }
    }


         

    上面是兩個(gè)用 Validator Annotations 注釋的 類. 每個(gè)屬性都用 約束限制了.  下面看看測(cè)試的類吧:

    TestValidator.java 類

    /*
    * Created on 2006-1-12
    * @author icerain
    */
    package test.annotation.validator;

    import org.hibernate.validator.ClassValidator;
    import org.hibernate.validator.InvalidValue;


    public class TestValidator {
      public void test() {
        Address add = new Address();
        add.setNum(0);
        add.setStreet("1");
        
        Person p = new Person();
        p.setAddress(add);
        p.setAge(0);
        p.setName("ice");
        
        /******************Test validator ********/
        // 注意該處只驗(yàn)證了Person 為了說(shuō)明 @Valid 注釋的使用
        ClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class);
        InvalidValue[] validMessages = classValidator.getInvalidValues(p);
        for (InvalidValue value : validMessages) {
          
        System.out.println("InvalidValue 的長(zhǎng)度是:" + validMessages.length
            +" . 驗(yàn)證消息是: " + value.getMessage()
            + " . PropertyPath 是:" + value.getPropertyPath()
            +" .\n\t PropertyName 是: " +value.getPropertyName()
            + "Value 是: " + value.getValue()
            +" Bean 是: "+ value.getBean()
            +"\n\t BeanClass 是:" + value.getBeanClass());
        }
      }
      
      public static void main(String[] args) {
        new TestValidator().test();
      }
    }



    程序的輸出如下

    InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:age .

    PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@dd87b2

    BeanClass 是:class test.annotation.validator.Person

    InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 長(zhǎng)度必須介于 4 與 2147483647 之間 . PropertyPath 是:name .

    PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@dd87b2

    BeanClass 是:class test.annotation.validator.Person

    InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:address.num .

    PropertyName 是: num. Value 是: 0 Bean 是: test.annotation.validator.Address@197d257

    BeanClass 是:class test.annotation.validator.Address

    InvalidValue 的長(zhǎng)度是:4 . 驗(yàn)證消息是: 長(zhǎng)度必須介于 3 與 8 之間 . PropertyPath 是:address.street .

    PropertyName 是: street. Value 是: 1 Bean 是: test.annotation.validator.Address@197d257

    BeanClass 是:class test.annotation.validator.Address

    可以看出不滿足約束的值都被指出了.

    同時(shí)該句: ClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class);

    我們只驗(yàn)證了 Person. 在Person里面的Address的屬性 由于有@Valid Annotations 所以 Address的相關(guān)屬性也被機(jī)聯(lián)驗(yàn)證了 .



    如果 把@Valid Annotations 去掉,結(jié)果如下:

    InvalidValue 的長(zhǎng)度是:2 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:age .

    PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@18fef3d

    BeanClass 是:class test.annotation.validator.Person

    InvalidValue 的長(zhǎng)度是:2 . 驗(yàn)證消息是: 長(zhǎng)度必須介于 4 與 2147483647 之間 . PropertyPath 是:name .

    PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@18fef3d

    BeanClass 是:class test.annotation.validator.Person

    可以看出 沒(méi)有驗(yàn)證 Address.



    當(dāng)然了 ,你還可以只驗(yàn)證一個(gè)屬性 , 沒(méi)有必要驗(yàn)證整個(gè)類.只需要在調(diào)用classValidator.getInvalidValues(p,"age")方法時(shí) 加上你要驗(yàn)證的屬性就可以了.如我們只想驗(yàn)證age 屬性 把代碼改為如下所示:

    InvalidValue[] validMessages = classValidator.getInvalidValues(p,"age"); //只驗(yàn)證age 屬性

    運(yùn)行結(jié)果如下:

    InvalidValue 的長(zhǎng)度是:1 . 驗(yàn)證消息是: 必須大于等于 1 . PropertyPath 是:age .

    PropertyName 是: age. Value 是: 0 Bean 是: test.annotation.validator.Person@1457cb

    BeanClass 是:class test.annotation.validator.Person

    只是驗(yàn)證了 age 屬性.



    怎么樣 ,很簡(jiǎn)單吧. 關(guān)于 Hibernate Validator 內(nèi)建的驗(yàn)證Annotations 大家可以看看 API 或者 參考文檔(中文版我正在翻譯中 請(qǐng)?jiān)L問(wèn)我的 Blog 獲得最新信息).

    如果你要寫(xiě)自己的約束呢 , 你不用擔(dān)心 ,這也是很容易的. 任何約束有兩部分組成: [約束描述符 即注釋]the constraint descriptor (the annotation) 和[約束validator 即 實(shí)現(xiàn)類] the constraint validator (the implementation class).下面我們擴(kuò)展Hibernate Test suit 中的一個(gè)Test 來(lái)講解一下.

    首先: 要聲明一個(gè)constraint descriptor .如下:

    package test.annotation.validator;

    import java.lang.annotation.Documented;
    import static java.lang.annotation.ElementType.TYPE;
    import static java.lang.annotation.ElementType.FIELD;
    import static java.lang.annotation.ElementType.METHOD;
    import java.lang.annotation.Retention;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    import java.lang.annotation.Target;

    import org.hibernate.validator.ValidatorClass;

    /**
    * Dummy sample of a bean-level validation annotation
    *
    * @author Emmanuel Bernard
    */
    @ValidatorClass(SerializabilityValidator.class)
    @Target({METHOD,FIELD,TYPE})
    @Retention(RUNTIME)
    @Documented
    public @interface Serializability {
      int num() default 11;
      String message() default "bean must be serialiable";
    }

    @ValidatorClass(SerializabilityValidator.class) 指出了 constraint validator 類.

    @Target({METHOD,FIELD,TYPE})
    @Retention(RUNTIME)
    @Documented
                    

    這幾個(gè)我就不用解釋了吧.

    Serializability 里面聲明了一個(gè) message 顯示約束的提示信息. num 只是為了說(shuō)明一個(gè)方面 在這里面沒(méi)有實(shí)際用途用 .

    然后就是 實(shí)現(xiàn)一個(gè)constraint validator 類 該類要實(shí)現(xiàn)Validator<ConstraintAnnotation>.這里是SerializabilityValidator.java 如下:

    //$Id: SerializabilityValidator.java,v 1.3 2005/11/17 18:12:11 epbernard Exp $
    package test.annotation.validator;

    import java.io.Serializable;

    import org.hibernate.validator.Validator;

    /**
    * Sample of a bean-level validator
    *
    * @author Emmanuel Bernard
    */
    public class SerializabilityValidator implements Validator<Serializability>, Serializable {
      public boolean isValid(Object value) {
       //這里只是Validator 里面的 實(shí)現(xiàn)驗(yàn)證規(guī)則的 方法. value 是要驗(yàn)證的值.
        System.out.println("IN SerializabilityValidator isValid:"+value.getClass()+": " +value.toString());
        return value instanceof Serializable;
      }

      public void initialize(Serializability parameters) {
        // 在這里可以 取得 constraint descriptor 里面的屬性 如上面我們聲明的 num
        System.out.println("IN SerializabilityValidator: parameters:"+ parameters.num() );
      }
    }


    然后在你的類中應(yīng)用@Serializability  就可以約束一個(gè)類實(shí)現(xiàn)Serializable 接口了. 如下:

    在我們的Person.java類 添加@Serializability  Annotations ,把Person.java 中的 //@Serializability //測(cè)試自定義約束 注釋去掉就ok了.

    運(yùn)行結(jié)果如下:

    InvalidValue 的長(zhǎng)度是:3 . 驗(yàn)證消息是: bean must be serialiable . PropertyPath 是:null .

    PropertyName 是: null. Value 是: test.annotation.validator.Person@1a73d3c Bean 是: test.annotation.validator.Person@1a73d3c

    BeanClass 是:class test.annotation.validator.Person

    現(xiàn)在把Person類實(shí)現(xiàn) java.io.Serializable 接口 則沒(méi)有出現(xiàn) 驗(yàn)證錯(cuò)誤消息.

    消息的國(guó)際化也是很簡(jiǎn)單的,把Serializability  中的message 改為以{}擴(kuò)住的 屬性文件的Key就可以了

    public @interface Serializability {
      int num() default 11;
      String message() default "{Serializable}"; //"bean must be serialiable"; //消息的國(guó)際化
    }


    然后編輯資料文件. 注意 該資源文件中要包括 Hibernate Validator 內(nèi)建的資源. 可以在該org\hibernate\validator\resources 包里面的資源文件基礎(chǔ)上修改 ,在打包里面 這樣就可以了. 自己打包可能不太方便.你可以把該包里面的文件復(fù)制出來(lái).然后放到你自己的項(xiàng)目包下在自己編輯, 該測(cè)試中 我是放在 test\resources 包下的.

    然后在 資源文件中添加 Serializable = '''''' 這么一行, 樣例如下:

    #DefaultValidatorMessages.properties (DefaultValidatorMessages_zh.properties 不再列出^_^)

     

    #下面是 Hibernate Validator 內(nèi)建的國(guó)際化消息

    validator.assertFalse=assertion failed

    validator.assertTrue=assertion failed

    validator.future=must be a future date

    validator.length=length must be between {min} and {max}

    validator.max=must be less than or equal to {value}

    validator.min=must be greater than or equal to {value}

    validator.notNull=may not be null

    validator.past=must be a past date

    validator.pattern=must match "{regex}"

    validator.range=must be between {min} and {max}

    validator.size=size must be between {min} and {max}

    #下面是自定義的消息

    Serializable=Bean not Serializable  //加上自己定義的國(guó)際化消息.

    在構(gòu)造ClassValidator 時(shí)要添上 資源文件 如下:(在測(cè)試類中)

    ClassValidator<Person> classValidator = new ClassValidator<Person> (Person.class,ResourceBundle.getBundle("test.resources.DefaultValidatorMessages"));//加載資源

    這樣就可以了 .  當(dāng)然 你還可以 更改 Hibernate Validator 的消息(不是在上面的資源文件中直接修改validator.length = ... 等等 ) , 還記得 Validator 注釋中有個(gè) message 元素嗎? 你以前用的都是默認(rèn)值,現(xiàn)在你可以該為你自己定義的了.如:validator.length 我把他改為 "該字符串的長(zhǎng)度不符合規(guī)定范圍范圍". 在資源文件中添加一行鍵值屬性對(duì)(key定義為 "myMsg")如下:

    myMsg=該字符串的長(zhǎng)度不符合規(guī)定范圍范圍

    并且還要在@Length 注釋中提供message的引用的key 如下@Length(min = 4,message = "{myMsg}")

    再一次運(yùn)行測(cè)試 ,我們就可以看到上面兩條自定義綁定的消息了 .如下:

    InvalidValue 的長(zhǎng)度是:3 . 驗(yàn)證消息是: Bean 不是 可 Serializable . PropertyPath 是:null .
    PropertyName 是: null. Value 是: test.annotation.validator.Person@1bd4722 Bean 是: test.annotation.validator.Person@1bd4722
    BeanClass 是:class test.annotation.validator.Person


    InvalidValue 的長(zhǎng)度是:3 . 驗(yàn)證消息是: 該字符串的長(zhǎng)度不符合規(guī)定范圍范圍 . PropertyPath 是:name .
    PropertyName 是: name. Value 是: ice Bean 是: test.annotation.validator.Person@1bd4722
    BeanClass 是:class test.annotation.validator.Person

    怎么樣,比你想象的簡(jiǎn)單吧.

    OK 上面我們討論了 Hibernate Validator 的主要用法: 但是 該框架有什么用呢? ^_^

    看到這里其實(shí)不用我在多說(shuō)了 大家都知道怎么用,什么時(shí)候用. 作為一篇介紹性文章我還是在此給出一個(gè)最常用的例子吧,更好的使用方式大家慢慢挖掘吧.

    比如 : 你現(xiàn)在在開(kāi)發(fā)一個(gè)人力資源(HR)系統(tǒng) (其實(shí)是我們ERP課程的一個(gè)作業(yè) ^_^), 里面要處理大量的數(shù)據(jù),尤其是在輸入各種資料時(shí) 如 登記員工信息. 如果你公司的員工的年齡要求是18 -- 60 那么你所輸入的年齡就不能超出這個(gè)范圍. 你可能會(huì)說(shuō)這很容易啊 , 不用Validator就可以解決啊.這保持?jǐn)?shù)據(jù)前驗(yàn)證就可以啦 如if ( e.getAge() > 60 || e.getAge() < 18 ) ........ 給出錯(cuò)誤信息 然后提示重新輸入不就OK啦 用得著 興師動(dòng)眾的來(lái)個(gè)第三方框架嗎?

    是啊 當(dāng)就驗(yàn)證這一個(gè)屬性時(shí), 沒(méi)有必要啊 ! 但是一個(gè)真正的HR 系統(tǒng),會(huì)只有一個(gè)屬性要驗(yàn)證嗎? 恐怕要有N多吧

    你要是每一個(gè)都那樣 寫(xiě)一段驗(yàn)證代碼 是不是很煩啊 ,況且也不方便代碼重用. 現(xiàn)在考慮一些 Validator 是不是更高效啊,攔截到 約束違例的 屬性 就可以直接得到 國(guó)際化的消息 可以把該消息顯示到一個(gè)彈出對(duì)話框上 提示更正  !

    Validator的用處不只這一種 ,你可以想到如何用呢 ! 歡迎發(fā)表你的高見(jiàn)!!

    OK 到此 我們的 Hibernate Validator 之旅就要先告一段落了 . 希望這是令你心曠神怡的一次寒冬之旅,

    把你學(xué)到的應(yīng)用到你的項(xiàng)目中吧,一定會(huì)提高你的生產(chǎn)率的. 相信我 ,沒(méi)錯(cuò)的  ^_^ !


    解析 Hibernate Validator

    icess 發(fā)表于 2006-01-19
    點(diǎn)擊數(shù):427 評(píng)論數(shù):0 評(píng)價(jià):5/1
    關(guān)鍵詞:Hibernate validator

    摘要:

    Hibernate Validator 可以是一個(gè)獨(dú)立的驗(yàn)證框架, 所以看完這篇分析 你可以把她獨(dú)立出來(lái)作為你的個(gè)人驗(yàn)證框架來(lái)使用了 ^_^(如果你有興趣和時(shí)間的話). Hibernate Validator 框架里面有兩個(gè)主要的類: ClassValidator 和InvalidValue 還有一個(gè)接口Validator,在這三個(gè)主要的構(gòu)件?最主要的就只有一個(gè) 那就是ClassValidator.另外兩個(gè)是很好理解的..
    在前一篇文章 < Hibernate Validator 簡(jiǎn)介 > http://www.matrix.org.cn/resource/article/44/44153_Hibernate%20Validator%20.html中,我們看到了Hibernate Validator的使用方法,和自定義驗(yàn)證Annotation的實(shí)現(xiàn)以及錯(cuò)誤消息的國(guó)際化等常見(jiàn)問(wèn)題.

    任何獲得Matrix授權(quán)的網(wǎng)站,轉(zhuǎn)載請(qǐng)保留以下作者信息和鏈接:
    作者:icess(作者的blog:http://blog.matrix.org.cn/page/icess)
    關(guān)鍵字:Hibernate Validator

    在使用如此優(yōu)雅的屬性驗(yàn)證框架的同時(shí),你是否想了解她的細(xì)節(jié)呢?她究竟是怎么實(shí)現(xiàn)的呢? 那么現(xiàn)在就跟隨我來(lái)探探她的內(nèi)核吧!

    Hibernate Validator 可以是一個(gè)獨(dú)立的驗(yàn)證框架, 所以看完這篇分析 你可以把她獨(dú)立出來(lái)作為你的個(gè)人驗(yàn)證框架來(lái)使用了 ^_^(如果你有興趣和時(shí)間的話). Hibernate Validator 框架里面有兩個(gè)主要的類: ClassValidator 和InvalidValue 還有一個(gè)接口Validator,在這三個(gè)主要的構(gòu)件中 最主要的就只有一個(gè) 那就是ClassValidator.另外兩個(gè)是很好理解的..

    現(xiàn)在就讓我們開(kāi)始吧. 遵循由淺入深的習(xí)慣 我們先看看 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接口就是我們自定義約束的實(shí)現(xiàn)類要繼承的接口,該接口在< Hibernate Validator 簡(jiǎn)介 > http://www.matrix.org.cn/resource/article/44/44153_Hibernate%20Validator%20.html中已經(jīng)討論過(guò)了,請(qǐng)參考.

    InvalidValue 類 大家看名字就應(yīng)該可以猜到她的作用了吧. 她就是代表一個(gè)沒(méi)有通過(guò)驗(yàn)證的錯(cuò)誤實(shí)例.該類定義了一些方法,通過(guò)這些方法你可以取得與該Validator Annotation 有關(guān)的一些參數(shù),如:她所注釋的屬性的值,錯(cuò)誤消息等等. 該類的源代碼如下:

    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余行,我都做了詳細(xì)的注釋如下:

    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 );  //重要的是該初始化函數(shù)
      }

      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>(); // 保存類級(jí)別的驗(yàn)證約束實(shí)現(xiàn)類
        memberValidators = new ArrayList<Validator>(); // 保存方法級(jí)別的驗(yàn)證約束實(shí)現(xiàn)類
        memberGetters = new ArrayList<Member>();// 保存類的成員(字段or方法)和構(gòu)造函數(shù)方法的標(biāo)識(shí)信息
        messages = new HashMap<Validator, String>(); // 利用Map保存與每個(gè)Validator相對(duì)應(yīng)的驗(yàn)證消息
        childGetters = new ArrayList<Member>();//  保存子類的成員(字段or方法)和構(gòu)造函數(shù)方法的標(biāo)識(shí)信息

        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 );//根據(jù)Annotation來(lái)得到Validator,參考對(duì)該函數(shù)的解釋
          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的所有超類和實(shí)現(xiàn)的接口添加的集合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 ); // 創(chuàng)建方法上的約束實(shí)現(xiàn)類(Validator), 參考對(duì)該函數(shù)的解釋
            Class clazz = method.getReturnType();// 得到該方法的返回類型
            createChildValidator( resourceBundle, method, clazz );// 創(chuàng)建子類的Validator
          }

          Field[] fields = currClass.getDeclaredFields(); // 掃描Field上面的注釋, 下面和上面Method的實(shí)現(xiàn)一樣
          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 );
          }
        }
      }

      /**
       * 創(chuàng)建內(nèi)嵌類的Validator. 如果該內(nèi)嵌類被Valid Annotation 注釋的話則
       * 創(chuàng)建另外一個(gè)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(實(shí)現(xiàn)了AnnotatedElement, GenericDeclaration, Member接口)
       * 得到 方法上的Annotations 然后利用私有方法createValidator(Annotation a)來(lái)創(chuàng)建
       * 每一個(gè)Annotation 的實(shí)現(xiàn)類 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 ); // 設(shè)置訪問(wèn)屬性
            memberGetters.add( member );
          }
        }
      }

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

      /**
       * 該方法產(chǎn)生了該Annotation的約束實(shí)現(xiàn)類 并初始化該類對(duì)應(yīng)的消息
       */
      private Validator createValidator(Annotation annotation) {
        try {
          //得到ValidatorClass Annotation
          ValidatorClass validatorClass = annotation.annotationType().getAnnotation( ValidatorClass.class );
          if ( validatorClass == null ) {
            return null;
          }
          // 然后 利用ValidatorClass Annotation 來(lái)得到里面的值(即實(shí)現(xiàn)該注釋的Class),
          //再利用Class 構(gòu)造一個(gè)instance
          Validator beanValidator = validatorClass.value().newInstance();
          beanValidator.initialize( annotation ); // 初始化Annotation中的參數(shù)(注意:在自定義約束中該方法有你來(lái)實(shí)現(xiàn))
          String messageTemplate = (String) annotation.getClass()
              .getMethod( "message", (Class[]) null )
              .invoke( annotation );  // 取得 constraint descriptor  中的message 的值
          String message = replace( messageTemplate, annotation ); // 初始化取得的模板消息 請(qǐng)參考 replace函數(shù)
          messages.put( beanValidator, message ); // 把message 放在map中,以便使用
          return beanValidator; // 返回 產(chǎn)生的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由關(guān)的,
          return EMPTY_INVALID_VALUE_ARRAY; //Avoid circularity
        }
        else {
          circularityState.add( bean );
        }

        if ( !beanClass.isInstance( bean ) ) { // 如果beanClass不是該bean的實(shí)例,則拋出異常
          throw new IllegalArgumentException( "not an instance of: " + bean.getClass() );
        }

        List<InvalidValue> results = new ArrayList<InvalidValue>();

        for ( int i = 0; i < beanValidators.size() ; i++ ) { // 驗(yàn)證類級(jí)別的約束
          Validator validator = beanValidators.get( i );
          if ( !validator.isValid( bean ) ) { //調(diào)用isValid方法,如果沒(méi)有通過(guò)則添加到list<InvalidValue>中
                            //如果是自定義約束則isValid方法 由你來(lái)實(shí)現(xiàn)
            results.add( new InvalidValue( messages.get( validator ), beanClass, null, bean, bean ) );
          }
        }

        for ( int i = 0; i < memberValidators.size() ; i++ ) {//驗(yàn)證方法級(jí)別的約束
          Member getter = memberGetters.get( i );
          if ( Hibernate.isPropertyInitialized(bean, getter.getName() ) ) {// ? 檢查該屬性是否已初始化
            Object value = getMemberValue( bean, getter );//利用反射 取得該屬性的值
            Validator validator = memberValidators.get( i ); //取得該約束的驗(yàn)證實(shí)現(xiàn)類
            if ( !validator.isValid( value ) ) {//調(diào)用isValid方法,如果沒(méi)有通過(guò)則添加到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 );// 通過(guò)參數(shù)value 得到 Class, 然后由Class作為key          //在childClassValidators map中得到其ClassValidator
                                         //如果不存在 則創(chuàng)建新的 ,然后再調(diào)用ClassValidator的getInvalidValues方法
              // 注意在調(diào)用getInvalidValues方法時(shí) 用到了circularityState 參數(shù), 當(dāng)調(diào)用循環(huán)一周時(shí) 返回(遞歸結(jié)束)
              for ( InvalidValue invalidValue : invalidValues ) {
                invalidValue.addParentBean( bean, propertyName );
                results.add( invalidValue ); //添加的結(jié)果中
              }
            }
          }
        }

        return results.toArray( new InvalidValue[results.size()] ); //返回InvalidValue數(shù)組
      }

      /**
       * 通過(guò)參數(shù)value 得到 Class, 然后由Class作為key 在childClassValidators map中得到其ClassValidator
       * 如果不存在 則創(chuàng)建新的 然后返回
       * @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.
       * 驗(yàn)證單個(gè)屬性的約束.
       */
      //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 ) ) {// 驗(yàn)證該屬性的約束
            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.
       * 驗(yàn)證 value 是否滿足當(dāng)前屬性的約束.
       */
      //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...)
       *該方法是與實(shí)體類綁定的 不推薦使用 有興趣的讀者可以自己研究一下
       * @param persistentClass hibernate metadata
       */
      public void apply(PersistentClass persistentClass) {  
       //源代碼省略
      }

      /**
       * 斷言該bean 是否符合所有約束. 負(fù)責(zé)拋出異常
       * @param bean
       */
      public void assertValid(T bean) {
        InvalidValue[] values = getInvalidValues( bean );
        if ( values.length > 0 ) {
          throw new InvalidStateException( values );
        }
      }

      /**
       * 該方法應(yīng)該是序列化ResourceBundle的 為private方法 但并沒(méi)有用到, 不知道為什么 可能以后會(huì)有用
       * @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;
      }

      /**
       * 該方法應(yīng)該是讀取序列化的ResourceBundle的 為private方法 但并沒(méi)有用到,不知道為什么 可能以后會(huì)有用
       * @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 );
      }
    }


    還記得我們?cè)隍?yàn)證時(shí)候所寫(xiě)的代碼嗎:

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


    只調(diào)用了classValidator的getInvalidValues(p);方法 我們就得到了InvalidValue[] validMessages, 該方法做了什么事情呢? 有上面的注釋看起來(lái)就輕松多了 ^_^.

    首先:在你創(chuàng)建ClassValidator時(shí), 會(huì)調(diào)用ClassValidator的構(gòu)造方法 她一供有三個(gè)構(gòu)造函數(shù) :
      

    有兩個(gè)構(gòu)造函數(shù)(一個(gè)傳遞要驗(yàn)證的類為參數(shù),一個(gè)還要加上你自定義的ResourceBundle)來(lái)供我們使用, 還有一個(gè)protected 的構(gòu)造函數(shù). 在構(gòu)造函數(shù)中都做了寫(xiě)什么呢?

    第一: 把要驗(yàn)證的類保存起來(lái),第二:決定使用的消息資源,如果你提供了自己的ResourceBundle 就使用自定義消息,否則使用默認(rèn)的消息資源.第三: 根據(jù)java反射機(jī)制,利用Annotation初始化所有的驗(yàn)證約束類,然后驗(yàn)證是否滿足驗(yàn)證條件.

    下面我們來(lái)關(guān)注一下initValidator 方法,看看是如何初始化驗(yàn)證約束類的. 現(xiàn)在請(qǐng)仔細(xì)看看 initValidator 里面的注釋.然后在繼續(xù)往下看.^_^

    通過(guò)上面的分析,可以看到在 initValidator函數(shù)中,初始化了你傳入類的所有的約束Annotations 的相關(guān)的東東(如: 其約束驗(yàn)證實(shí)現(xiàn)類, 如果有內(nèi)嵌的類,如果該類被Valid Annotation注釋的話 也構(gòu)造一個(gè)內(nèi)嵌類的Validator 并初始化其相關(guān)的東東 如此遞歸執(zhí)行下去).該函數(shù)執(zhí)行完后,可以說(shuō)構(gòu)造了一個(gè)以你傳入的類為跟的 約束注釋樹(shù)(自創(chuàng)的名詞,不了解也沒(méi)關(guān)系 ^_^),然后由此樹(shù)來(lái)逐個(gè)驗(yàn)證沒(méi)有個(gè)約束.此時(shí)已經(jīng)具備驗(yàn)證約束的條件了.你只有調(diào)用classValidator.getInvalidValues(p)方法就可以驗(yàn)證類p 上的所有約束了.

    GetInvalidValues()方法有做了什么呢, 現(xiàn)在你要再回到上面看看她的注釋了  ^_^:

    怎么樣現(xiàn)在知道 GetInvalidValues 做了什么了吧.她就是取出 約束注釋樹(shù)中的每一個(gè)約束注釋(分為 類注釋, 方法注釋, 屬性注釋 和內(nèi)嵌類注釋 (也就是類里面的類屬性)),并驗(yàn)證相應(yīng)的成員是否滿足該約束注釋的要求,也就是調(diào)用Validator的isValid() 方法.最后用不滿足要求的 成員信息構(gòu)造InvalidValue 數(shù)組 并返. ClassValidator 類我們基本上已經(jīng)講解完了,剩下的該Validatro里面的就是一些內(nèi)建的約束Annotation和約束驗(yàn)證實(shí)現(xiàn)類了,這些看看前一篇文章就明白怎么回事了.到此 HibernateValidator 框架基本上分析完了. 通過(guò)分析該框架.讓我看到了Annotation的一種高級(jí)用法的實(shí)現(xiàn)機(jī)制,和反射機(jī)制的巧妙應(yīng)用,以及幾個(gè)巧妙的設(shè)計(jì)模式(我就不在舉例了 大家可以相互探討一下). 你從中學(xué)到了什么呢?

    對(duì)想把Hibernate Validator做成一個(gè)獨(dú)立框架的幾點(diǎn)說(shuō)明:

    1.去掉apply 函數(shù).

    2. 在getPropertyName 和 getMemberValue 中 如果得到的值為null 則拋出org.hibernate.AssertionFailure異常. 可以重寫(xiě)該異常,或者從Hibernate源代碼中提取(建議重寫(xiě)).

    3.用到了Hibernate.isPropertyInitialized(Object o,String name)方法 判斷該類(o)的屬性(name)是否以及加載的, 該函數(shù)的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即代表沒(méi)有賦初值(可能違反約束);否則驗(yàn)證該值是否違反約束.

    4.里面還用到了org.hibernate.util.IdentitySet 一個(gè)set實(shí)現(xiàn),可以自己實(shí)現(xiàn)或者從Hibernate中提取(推薦提取);

    這樣一個(gè)獨(dú)立的Validation frameWork 就出來(lái)了. 不依賴任何第三方代碼,完全可以作為你自己的驗(yàn)證框架在項(xiàng)目中使用.

    資源:
    PS: 關(guān)于在實(shí)體類上(持久化層)使用Validator是否有好處,
    大家可以看看:http://www.hibernate.org.cn/viewtopic.php?t=18131
    posted on 2006-02-05 10:17 黑咖啡 閱讀(8083) 評(píng)論(1)  編輯  收藏 所屬分類: tec

    FeedBack:
    # re: Hibernate Validator
    2012-06-28 19:42 | datong
    這個(gè)用了,第一次預(yù)熱會(huì)消耗性能73毫秒左右!  回復(fù)  更多評(píng)論
      

    <2012年6月>
    272829303112
    3456789
    10111213141516
    17181920212223
    24252627282930
    1234567

    留言簿(2)

    隨筆分類(67)

    文章分類(43)

    Good Article

    Good Blogs

    Open Source

    最新隨筆

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 四虎在线视频免费观看视频| 阿v免费在线观看| 亚洲欧洲精品在线| 亚洲av无码不卡| 久久久青草青青亚洲国产免观| 亚洲无线一二三四区手机| 亚洲国产综合久久天堂| 免费国产一级特黄久久| 亚洲国产成人久久一区久久| 亚洲国产高清在线一区二区三区| 无码欧精品亚洲日韩一区夜夜嗨| 免费一级特黄特色大片在线| 亚洲国产av无码精品| 国产亚洲精品国看不卡| 亚洲午夜久久久影院伊人| 国产亚洲精品va在线| 久久久无码精品亚洲日韩蜜臀浪潮| 在线电影你懂的亚洲| 亚洲一级毛片中文字幕| 亚洲熟妇av午夜无码不卡| 亚洲午夜无码久久| 猫咪www免费人成网站| GOGOGO高清免费看韩国| 鲁丝片一区二区三区免费| 免费福利视频导航| 午夜精品在线免费观看| 亚洲精品无码久久不卡| 国产AV无码专区亚洲精品| 亚洲成aⅴ人片在线观| 亚洲av无码偷拍在线观看| 日韩毛片免费一二三| 18禁超污无遮挡无码免费网站| 亚洲成人免费网址| 日韩一品在线播放视频一品免费| 亚洲精品一级无码鲁丝片| 亚洲成av人片天堂网| 亚洲永久在线观看| 一级特黄色毛片免费看| 中文字幕免费在线观看| 国内大片在线免费看| 亚洲人精品午夜射精日韩|