風(fēng)行天下

          JAVA太極
          posts - 4, comments - 10, trackbacks - 0, articles - 55
            BlogJava :: 首頁(yè) :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

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

          Posted on 2005-08-15 12:28 風(fēng)太少 閱讀(371) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): struts
          摘要:
          既然是說(shuō)Struts源代碼,為什么要講Commons-Beanutils包呢?原因很簡(jiǎn)單,Struts的DynaFormBean就是通過(guò)這個(gè)包里的相關(guān)類(lèi)實(shí)現(xiàn)的。本文對(duì)Commons-Beanutils 源代碼進(jìn)行了分析..


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

          Commons-Beanutils(一)

          Commons-Beanutils 這個(gè)是jakarta commons項(xiàng)目中的一個(gè)子項(xiàng)目。這個(gè)項(xiàng)目開(kāi)發(fā)的目的是幫助開(kāi)發(fā)者動(dòng)態(tài)的獲取/設(shè)值Java Bean的屬性,同時(shí)解決每次都要寫(xiě)getXXX和setXXX的麻煩。

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

          二、特殊的實(shí)現(xiàn)
          1、對(duì)于ClassConverter類(lèi),當(dāng)進(jìn)入第三種情形的時(shí)候,實(shí)際執(zhí)行的是
          ClassLoader classLoader =Thread.currentThread().getContextClassLoader();
             if (classLoader == null) {
                 classLoader = ClassConverter.class.getClassLoader();
             }
             return (classLoader.loadClass(value.toString()));


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

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

          Commons-Beanutils(二)

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

          二、 XXXLocaleConverter
          把pattern格式的value轉(zhuǎn)換成標(biāo)準(zhǔn)格式的相應(yīng)的XXX類(lèi)。這些類(lèi)可以分為兩大類(lèi):一類(lèi)為時(shí)間,一類(lèi)為數(shù)值。
          1、時(shí)間類(lèi)最后都會(huì)通過(guò)SimpleDateFormat類(lèi)對(duì)值進(jìn)行轉(zhuǎn)換,程序如下:
           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、數(shù)值類(lèi)最后都會(huì)通過(guò)DecimalFormat類(lèi)對(duì)值進(jìn)行轉(zhuǎn)換,程序如下:
          DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(locale);
             if (pattern != null) {
                 if (locPattern) {
                     formatter.applyLocalizedPattern(pattern);
                 } else {
                     formatter.applyPattern(pattern);
                 }
             }
             return formatter.parse((String) value);

          這個(gè)轉(zhuǎn)化過(guò)程要注意精度的問(wèn)題。由于Number類(lèi)是所有的數(shù)值類(lèi)的父類(lèi),所以轉(zhuǎn)換完成后要檢查最后的結(jié)果是否是當(dāng)前要求的精度:如果大于所要求的精度,則拋出ConversionException異常。

          Commons-Beanutils(三)

          Dyna開(kāi)頭的類(lèi),是專(zhuān)門(mén)為DynaFormBean而設(shè)計(jì)的。

          一、DynaBean,DynaClass 與 DynaProperty
          DynaBean并不是Java中所定義的Bean,而是一種“假”的Bean。因?yàn)樗⒉皇峭ㄟ^(guò)getXXX和setXXX方法,對(duì)XXX屬性進(jìn)行取值和設(shè)值的。它通過(guò)一個(gè)實(shí)現(xiàn)了DynaClass接口的類(lèi),幫助管理其所有的屬性的類(lèi)別,而自己則管理對(duì)XXX屬性值的設(shè)定和獲取。在設(shè)值的時(shí)候會(huì)通過(guò)與name對(duì)應(yīng)的DynaProperty對(duì)象,檢查賦值的類(lèi)別是否正確。
          DynaProperty類(lèi)描述的是DynaBean中所包含的屬性的類(lèi)型。DynaProperty類(lèi)有三個(gè)屬性:屬性的名稱(chēng):name,屬性的名稱(chēng);type,屬性的類(lèi)別;contentType,如果DynaProperty描述的是個(gè)容器對(duì)象(List或者M(jìn)ap),那么這個(gè)contentType就代表這個(gè)容器內(nèi)元素的類(lèi)別。這個(gè)類(lèi)值得關(guān)注的地方是writeObject和readObject方法的實(shí)現(xiàn)。它會(huì)首先判斷自己的type是否是一個(gè)primitive的類(lèi),如果是,則先寫(xiě)入true標(biāo)志,再寫(xiě)入對(duì)應(yīng)的primitive類(lèi)的編號(hào);否則寫(xiě)入false標(biāo)志,再寫(xiě)入type。因?yàn)樵谡{(diào)用readObject方法時(shí),如果得出的是primitive類(lèi)型,則type的值為XXX.TYPE而不是XXX.class。
          DynaClass 是一個(gè)接口,用來(lái)管理DynaBean中所有的DynaProperty屬性。

          二、BasiceDyanBean 與 BasicDynaClass
          BasiceDyanBean 實(shí)現(xiàn)自DynaBean接口。它包含一個(gè)實(shí)現(xiàn)了DynaClass接口的類(lèi)的對(duì)象,和一個(gè)用來(lái)存放值的HashMap。這個(gè)HashMap的key與DynaClass中HashMap的key是一一對(duì)應(yīng)的。
          BasicDynaClass 實(shí)現(xiàn)了DynaClass接口,以DynaProperty的name為key保存所有這些DynaProperty對(duì)象。它通過(guò)newInstance方法動(dòng)態(tài)生成實(shí)現(xiàn)了DynaBean接口的類(lèi)的對(duì)象;注意這個(gè)類(lèi)是可以動(dòng)態(tài)指定的,如果沒(méi)有,那么就是默認(rèn)的BasicDynaBean類(lèi)。動(dòng)態(tài)指定類(lèi)是通過(guò)反射實(shí)現(xiàn)的,程序如下:
          //dynaBeanClass為任意的實(shí)現(xiàn)了DynaBean接口的類(lèi),constructorTypes為這個(gè)
          //類(lèi)的構(gòu)造方法所需要的參數(shù)的類(lèi)型
          constructor = dynaBeanClass.getConstructor(constructorTypes);
          //constructorValues為構(gòu)造方法的參數(shù)值,實(shí)際上它的值為當(dāng)前的BasicDynaClass
          return ((DynaBean) constructor.newInstance(constructorValues));

          Commons-Beanutils(四)

          一、ConvertUtils 和 ConvertUtilsBean
          ConvertUtils 是ConvertUtilsBean類(lèi)的一個(gè)簡(jiǎn)單封裝,即ConvertUtils中的所有方法都是通過(guò)直接調(diào)用ConvertUtilsBean中的同名方法實(shí)現(xiàn)的。如果你需要更復(fù)雜的功能,就使用ConvertUtilsBean,否則使用ConvertUtils。
          ConvertUtilsBean 通過(guò)一個(gè)HashMap管理所有的XXXConverter。這個(gè)HashMap的key為XXX的類(lèi)全名,值為相應(yīng)的XXXConverter對(duì)象。通過(guò)deregister()方法,初始化這個(gè)HashMap。這個(gè)初始化方法會(huì)為每一個(gè)XXXConverter類(lèi)提供一個(gè)缺省的值。用戶(hù)可以動(dòng)過(guò)setDefaultXXX(...)方法來(lái)自行設(shè)置XXXConverter對(duì)象的缺省值。這個(gè)類(lèi)還提供了convert(...)方法,對(duì)String value進(jìn)行相應(yīng)的轉(zhuǎn)化。

          二、PropertyUtils 和 PropertyUtilsBean
          PropertyUtils 是PropertyUtilsBean類(lèi)的一個(gè)簡(jiǎn)單封裝,同樣它的所有方法都是通過(guò)直接調(diào)用PropertyUtilsBean 中同名方法實(shí)現(xiàn)的。
          PropertyUtilsBean 對(duì)DynaBean或者一個(gè)java標(biāo)準(zhǔn)Bean中的屬性動(dòng)態(tài)的賦值和取值(非通過(guò)getXXX和setXXX方法)。
          1、這個(gè)類(lèi)支持多層嵌套,比如:XXX[i].YYY(key).ZZZ,那么它會(huì)為你得到或者設(shè)置ZZZ的屬性。
          2、所有的set/get方法介紹:
          //對(duì)XXX(key)格式的name設(shè)值
          setMappedProperty(Object bean, String name,String key, Object value)
          //對(duì)XXX[i]格式的name設(shè)值
          setIndexedProperty(Object bean, String name, int index, Object value)
          //對(duì)XXX格式的name設(shè)值
          setSimpleProperty(Object bean, String name, Object value)
          //對(duì)XXX(key).YYY[i].ZZZ格式的名稱(chēng)設(shè)值。注意,name必須要遵照這種格式。
          //這個(gè)方法實(shí)際做的就是以“.”為分隔符,逐層的根據(jù)情況分別調(diào)用上面的幾個(gè)方法,
          //獲取相應(yīng)的bean。
          setNestedProperty(Object bean, String name, Object value)
          //它直接調(diào)用setNestedProperty方法
          setProperty(Object bean, String name, Object value)
          3、getPropertyType(Object bean, String name)方法中用來(lái)獲取Bean的某一個(gè)property的類(lèi)型的代碼:
          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)
          這個(gè)方法用來(lái)獲取一個(gè)數(shù)組或者一個(gè)List中的屬性。它會(huì)首先看這個(gè)bean是否是DynaBean類(lèi)型的,如果是,再其檢查是否有name這個(gè)屬性,如果有那么就直接調(diào)用get(String name, int index)方法返回值;如果不是DynaBean類(lèi)型,那么就會(huì)執(zhí)行如下方法:
          //有沒(méi)有為數(shù)組的某個(gè)特定元素取值的方法
          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));
          }
          }
          // 如果沒(méi)有,就先取出整個(gè)對(duì)象
          Method readMethod = getReadMethod(descriptor);
          if (readMethod == null) {
          throw new NoSuchMethodException("Property '" + name +
          "' has no getter method");
          }
          Object value = invokeMethod(readMethod, bean, new Object[0]);
          //如果這個(gè)對(duì)象實(shí)際上是一個(gè)List,那么調(diào)用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);
          }
          //否則通過(guò)Array類(lèi)提供的相應(yīng)方法取值
          } else {
          //get the array's value
          return (Array.get(value, index));
          }

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

          //這種類(lèi)型轉(zhuǎn)換的原則是:如果value是String或者String[],那么這個(gè)值可能為任意的類(lèi)型, 
              //需要進(jìn)行轉(zhuǎn)換。如果為其它的類(lèi)型,則不進(jìn)行任何轉(zhuǎn)換。
              if (type.isArray() && (index < 0)) {
                  // 如果是直接對(duì)一個(gè)數(shù)組賦值,則使用convert(String values[], Class clazz)方法轉(zhuǎn)換
                  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()) {
                  // 如果是對(duì)數(shù)組的某一個(gè)元素賦值,則使用convert(String value, Class clazz)方法轉(zhuǎn)換
                  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 {                 
                  // 否則就是一對(duì)一的簡(jiǎn)單賦值,則使用convert(String value, Class clazz)方法轉(zhuǎn)換
                  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;        }
              }

          只有注冊(cè)用戶(hù)登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 彰化市| 墨玉县| 施甸县| 九台市| 永年县| 洪湖市| 榆林市| 浦东新区| 高尔夫| 富裕县| 宁乡县| 开封县| 古丈县| 仁寿县| 罗平县| 淮阳县| 常宁市| 嘉定区| 调兵山市| 辽宁省| 桃园县| 贵州省| 汉源县| 太和县| 龙江县| 金沙县| 招远市| 乌什县| 靖宇县| 喜德县| 赤峰市| 息烽县| 昌黎县| 汶上县| 巴中市| 敦煌市| 通州区| 丰台区| 哈尔滨市| 莱州市| 钦州市|