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

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

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

    風行天下

    JAVA太極
    posts - 4, comments - 10, trackbacks - 0, articles - 55
      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理

    struts源代碼閱讀(Commons-Beanutils包)

    Posted on 2005-08-15 12:28 風太少 閱讀(366) 評論(0)  編輯  收藏 所屬分類: struts
    摘要:
    既然是說Struts源代碼,為什么要講Commons-Beanutils包呢?原因很簡單,Struts的DynaFormBean就是通過這個包里的相關類實現的。本文對Commons-Beanutils 源代碼進行了分析..


    本文Matrix永久鏡像:http://www.matrix.org.cn/resource/article/1/1708_struts.html
    說明:本文可能由Matrix原創,也可能由Matrix的會員整理,或者由
    Matrix的Crawler在全球知名Java或者其他技術相關站點抓取并永久
    保留鏡像,Matrix會保留所有原來的出處URL,并在顯著地方作出說明,
    如果你發覺出處URL有誤,請聯系Matrix改正.
    既然是說Struts源代碼,為什么要講Commons-Beanutils包呢?原因很簡單,Struts的DynaFormBean就是通過這個包里的相關類實現的。同樣,留下我的郵箱,方便和大家共同交流。我的郵箱是:mariah_fan@hotmail.com。

    Commons-Beanutils(一)

    Commons-Beanutils 這個是jakarta commons項目中的一個子項目。這個項目開發的目的是幫助開發者動態的獲取/設值Java Bean的屬性,同時解決每次都要寫getXXX和setXXX的麻煩。

    一、XXXConvert
    這些類都實現Converter接口,提供把value值轉化成為相應XXX類的實現。現在只針對四種類型:數字,時間,Boolean和String。在Converter 接口中只有一個方法convert(Class type, Object value),把value對象轉換為type所要求的類。XXXConvert類中這個方法的思路是:
    1、如果value==null,并且自己內部有缺省的值那么就返回這個缺省的值。如果沒有缺省值,就拋出ConversionException異常。
    2、如果value instanceOf XXX類,那么就直接返回value。
    3、如果上面的都不行,那么調用new XXX(value.toString())或者XXX.valueOf(value.toString())方法來返回。轉化失敗時,拋出ConversionException異常。

    二、特殊的實現
    1、對于ClassConverter類,當進入第三種情形的時候,實際執行的是
    ClassLoader classLoader =Thread.currentThread().getContextClassLoader();
       if (classLoader == null) {
           classLoader = ClassConverter.class.getClassLoader();
       }
       return (classLoader.loadClass(value.toString()));


    2、對于BooleanConverter類,當進入第三種情形的時候,實際執行的是,根據value.toString()的值:yes,y,true, on, 1 返回true;no,n,false,off,0 返回false。如果這些情形都不符合,并且有缺省值的時候則返回缺省值。否則拋出ConversionException;

    三、XXXArrayConverter
    這些類繼承自AbstractArrayConverter類。 AbstractArrayConverter 實際只實現了一個List parseElements(String svalue)方法。這個方法接受的是{value1, value2,...}格式的字符串,逐個解析出來后,放入一個ArrayList中。它通過StreamTokenizer解析字符串:StreamTokenizer是用來分離input stream中讀取的字符串,并且可以根據標記區分不同的內容,比如數字,字符或者注釋。XXXArrayConverter由于要轉換的是一個數組,所以convert(....)方法的實現過程有所不同。
    1、如果value==null,并且自己內部有缺省的值那么就返回這個缺省的值。如果沒有缺省值,就拋出ConversionException異常。
    2、如果model.getClass() == value.getClass(),那么就直接返回value。
    3、如果上面的都不行,那么就通過parseElements(value.toString())生成一個數組,再對數組的元素逐個調用new XXX(list.get(i))或者XXX.valueOf(list.get(i))方法,轉換成為數組對元素要求的類型。轉化失敗時,拋出ConversionException異常。

    Commons-Beanutils(二)

    一、LocaleConverter 與 BaseLocaleConverter
    LocaleConverter繼承自 Converter接口,定義了一個新方法convert(Class type, Object value, String pattern)。
    抽象類BaseLocaleConverter實現了LocaleConverter接口。它的locPattern屬性用來表示這個對象的pattern是否是本地化的格式。patttern 是指把何種格式的時間或者數字值轉換成標準值。convert(...)的執行過程是:
    1、如果value==null,并且自己內部有缺省的值那么就返回這個缺省的值。如果沒有缺省值,就拋出ConversionException異常。
    2、根據參數pattern值是否為null,調用parse(Object value, String pattern)方法:如果這個參數不為null那么就使用這個參數的值,否則使用對象預存的pattern值。如果這
    樣做引起了異常,會首先判斷是否能夠返回缺省的值,不能則拋出ConversionException異常。
    3、parse(Object value, String
    pattern)方法的實現被拋至繼承了它的類具體實現。這個方法雖然把value值表述為Object類型,但是最后都是通過強制轉換,轉換成為String類型。也就是說它實際上需要的
    是String類型的value。

    二、 XXXLocaleConverter
    把pattern格式的value轉換成標準格式的相應的XXX類。這些類可以分為兩大類:一類為時間,一類為數值。
    1、時間類最后都會通過SimpleDateFormat類對值進行轉換,程序如下:
     if(pattern == null) {      
           pattern = locPattern ? new SimpleDateFormat().toLocalizedPattern() :
                     new SimpleDateFormat().toPattern();
       }
       SimpleDateFormat format = new SimpleDateFormat(pattern, locale);
       if (locPattern) {
           formatter.applyLocalizedPattern(pattern);
       }else {
           formatter.applyPattern(pattern);
       }
       return formatter.parse((String) value);


    2、數值類最后都會通過DecimalFormat類對值進行轉換,程序如下:
    DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(locale);
       if (pattern != null) {
           if (locPattern) {
               formatter.applyLocalizedPattern(pattern);
           } else {
               formatter.applyPattern(pattern);
           }
       }
       return formatter.parse((String) value);

    這個轉化過程要注意精度的問題。由于Number類是所有的數值類的父類,所以轉換完成后要檢查最后的結果是否是當前要求的精度:如果大于所要求的精度,則拋出ConversionException異常。

    Commons-Beanutils(三)

    Dyna開頭的類,是專門為DynaFormBean而設計的。

    一、DynaBean,DynaClass 與 DynaProperty
    DynaBean并不是Java中所定義的Bean,而是一種“假”的Bean。因為它并不是通過getXXX和setXXX方法,對XXX屬性進行取值和設值的。它通過一個實現了DynaClass接口的類,幫助管理其所有的屬性的類別,而自己則管理對XXX屬性值的設定和獲取。在設值的時候會通過與name對應的DynaProperty對象,檢查賦值的類別是否正確。
    DynaProperty類描述的是DynaBean中所包含的屬性的類型。DynaProperty類有三個屬性:屬性的名稱:name,屬性的名稱;type,屬性的類別;contentType,如果DynaProperty描述的是個容器對象(List或者Map),那么這個contentType就代表這個容器內元素的類別。這個類值得關注的地方是writeObject和readObject方法的實現。它會首先判斷自己的type是否是一個primitive的類,如果是,則先寫入true標志,再寫入對應的primitive類的編號;否則寫入false標志,再寫入type。因為在調用readObject方法時,如果得出的是primitive類型,則type的值為XXX.TYPE而不是XXX.class。
    DynaClass 是一個接口,用來管理DynaBean中所有的DynaProperty屬性。

    二、BasiceDyanBean 與 BasicDynaClass
    BasiceDyanBean 實現自DynaBean接口。它包含一個實現了DynaClass接口的類的對象,和一個用來存放值的HashMap。這個HashMap的key與DynaClass中HashMap的key是一一對應的。
    BasicDynaClass 實現了DynaClass接口,以DynaProperty的name為key保存所有這些DynaProperty對象。它通過newInstance方法動態生成實現了DynaBean接口的類的對象;注意這個類是可以動態指定的,如果沒有,那么就是默認的BasicDynaBean類。動態指定類是通過反射實現的,程序如下:
    //dynaBeanClass為任意的實現了DynaBean接口的類,constructorTypes為這個
    //類的構造方法所需要的參數的類型
    constructor = dynaBeanClass.getConstructor(constructorTypes);
    //constructorValues為構造方法的參數值,實際上它的值為當前的BasicDynaClass
    return ((DynaBean) constructor.newInstance(constructorValues));

    Commons-Beanutils(四)

    一、ConvertUtils 和 ConvertUtilsBean
    ConvertUtils 是ConvertUtilsBean類的一個簡單封裝,即ConvertUtils中的所有方法都是通過直接調用ConvertUtilsBean中的同名方法實現的。如果你需要更復雜的功能,就使用ConvertUtilsBean,否則使用ConvertUtils。
    ConvertUtilsBean 通過一個HashMap管理所有的XXXConverter。這個HashMap的key為XXX的類全名,值為相應的XXXConverter對象。通過deregister()方法,初始化這個HashMap。這個初始化方法會為每一個XXXConverter類提供一個缺省的值。用戶可以動過setDefaultXXX(...)方法來自行設置XXXConverter對象的缺省值。這個類還提供了convert(...)方法,對String value進行相應的轉化。

    二、PropertyUtils 和 PropertyUtilsBean
    PropertyUtils 是PropertyUtilsBean類的一個簡單封裝,同樣它的所有方法都是通過直接調用PropertyUtilsBean 中同名方法實現的。
    PropertyUtilsBean 對DynaBean或者一個java標準Bean中的屬性動態的賦值和取值(非通過getXXX和setXXX方法)。
    1、這個類支持多層嵌套,比如:XXX[i].YYY(key).ZZZ,那么它會為你得到或者設置ZZZ的屬性。
    2、所有的set/get方法介紹:
    //對XXX(key)格式的name設值
    setMappedProperty(Object bean, String name,String key, Object value)
    //對XXX[i]格式的name設值
    setIndexedProperty(Object bean, String name, int index, Object value)
    //對XXX格式的name設值
    setSimpleProperty(Object bean, String name, Object value)
    //對XXX(key).YYY[i].ZZZ格式的名稱設值。注意,name必須要遵照這種格式。
    //這個方法實際做的就是以“.”為分隔符,逐層的根據情況分別調用上面的幾個方法,
    //獲取相應的bean。
    setNestedProperty(Object bean, String name, Object value)
    //它直接調用setNestedProperty方法
    setProperty(Object bean, String name, Object value)
    3、getPropertyType(Object bean, String name)方法中用來獲取Bean的某一個property的類型的代碼:
    PropertyDescriptor descriptor = getPropertyDescriptor(bean, name);
    if (descriptor == null) {
    return (null);
    }else if (descriptor instanceof IndexedPropertyDescriptor) {
    return (((IndexedPropertyDescriptor) descriptor).getIndexedPropertyType());
    } else if (descriptor instanceof MappedPropertyDescriptor) {
    return (((MappedPropertyDescriptor) descriptor).getMappedPropertyType());
    } else {
    return (descriptor.getPropertyType());
    }
    4、getIndexedProperty(Object bean, String name, int index)
    這個方法用來獲取一個數組或者一個List中的屬性。它會首先看這個bean是否是DynaBean類型的,如果是,再其檢查是否有name這個屬性,如果有那么就直接調用get(String name, int index)方法返回值;如果不是DynaBean類型,那么就會執行如下方法:
    //有沒有為數組的某個特定元素取值的方法
    if (descriptor instanceof IndexedPropertyDescriptor) {
    Method readMethod = ((IndexedPropertyDescriptor) descriptor).
    getIndexedReadMethod();
    if (readMethod != null) {
    Object subscript[] = new Object[1];
    subscript[0] = new Integer(index);
    return (invokeMethod(readMethod,bean, subscript));
    }
    }
    // 如果沒有,就先取出整個對象
    Method readMethod = getReadMethod(descriptor);
    if (readMethod == null) {
    throw new NoSuchMethodException("Property '" + name +
    "' has no getter method");
    }
    Object value = invokeMethod(readMethod, bean, new Object[0]);
    //如果這個對象實際上是一個List,那么調用get()方法
    if (!value.getClass().isArray()) {
    if (!(value instanceof java.util.List)) {
    throw new IllegalArgumentException("Property '" + name
    + "' is not indexed");
    } else {
    //get the List's value
    return ((java.util.List) value).get(index);
    }
    //否則通過Array類提供的相應方法取值
    } else {
    //get the array's value
    return (Array.get(value, index));
    }

    三、BeanUtil 和 BeanUtilBean
    BeanUtils 是BeanUtilsBean類的一個簡單封裝,同樣它的所有方法都是通過直接調用BeanUtilsBean 中同名方法實現的。
    BeanUtilBean中大多數核心方法都是通過調用PropertyUtilsBean中的方法實現的。而populate(Object bean, Map properties)是自己實現的,因為這個賦值過程要首先對value進行格式的轉化;這個方法把properties中的key為屬性名,value為屬性的值,分別對應的設值給bean對象。它通過setProperty(Object bean, String name, Object value)方法實現逐個設值的。由于此時的value不一定符合bean中name屬性的類型,所以首先要把value轉換成合適的值,然后再設值。具體的類型轉換方法如下:

    //這種類型轉換的原則是:如果value是String或者String[],那么這個值可能為任意的類型, 
        //需要進行轉換。如果為其它的類型,則不進行任何轉換。
        if (type.isArray() && (index < 0)) {
            // 如果是直接對一個數組賦值,則使用convert(String values[], Class clazz)方法轉換
            if (value == null) {
                String values[] = new String[1];
                values[0] = (String) value;
                newValue = getConvertUtils().convert((String[]) values, type);
            } else if (value instanceof String) {
                String values[] = new String[1];
                values[0] = (String) value;
                newValue = getConvertUtils().convert((String[]) values, type);
            } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert((String[]) value, type);
            } else {
                newValue = value;
            }
        } else if (type.isArray()) {
            // 如果是對數組的某一個元素賦值,則使用convert(String value, Class clazz)方法轉換
            if (value instanceof String) {
                newValue = getConvertUtils().convert((String) value, type.getComponentType());
            } else if (value instanceof String[]) {   
                newValue = getConvertUtils().convert(((String[]) value)[0],type.getComponentType());
            } else {
                newValue = value;     
            }
        } else {                 
            // 否則就是一對一的簡單賦值,則使用convert(String value, Class clazz)方法轉換
            if ((value instanceof String) || (value == null)) {
                newValue = getConvertUtils().convert((String) value, type);
            } else if (value instanceof String[]) {
                newValue = getConvertUtils().convert(((String[]) value)[0], type);       
            } else if (getConvertUtils().lookup(value.getClass()) != null) {
                newValue = getConvertUtils().convert(value.toString(), type);
            } else {
                newValue = value;        }
        }
    主站蜘蛛池模板: 亚洲国产亚洲综合在线尤物| 亚洲国产成人片在线观看无码| 亚洲永久中文字幕在线| 无码午夜成人1000部免费视频| 亚洲精品乱码久久久久久自慰| 成年女人A毛片免费视频| 国产亚洲成人在线播放va| 国产免费牲交视频免费播放 | 久九九精品免费视频| 亚洲视频网站在线观看| 黄在线观看www免费看| 亚洲中文字幕日本无线码| 免费观看理论片毛片| 污污视频免费观看网站| 精品国产亚洲男女在线线电影 | 成年女人视频网站免费m| 亚洲AV无码AV男人的天堂不卡| 国产精品免费看久久久无码| 日本亚洲高清乱码中文在线观看| 免费国产真实迷j在线观看| 一级做a爱过程免费视| 亚洲日韩欧洲乱码AV夜夜摸| 无码A级毛片免费视频内谢| 亚洲国产日韩在线| 日本无吗免费一二区| 一区二区三区免费看| 亚洲成人动漫在线| 成人免费毛片内射美女APP| 无人视频免费观看免费视频| 亚洲午夜福利在线观看| 亚洲视频免费观看| 久久精品国产亚洲AV电影网| 亚洲午夜精品一级在线播放放 | 久久久久国产精品免费看| 色播亚洲视频在线观看| 91成年人免费视频| 国产成人+综合亚洲+天堂| 国产精品久久久亚洲| 久久久高清免费视频| 亚洲国产免费综合| 亚洲一区无码中文字幕乱码|