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)的。本文對(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í)行的是
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)換,程序如下:
2、數(shù)值類(lèi)最后都會(huì)通過(guò)DecimalFormat類(lèi)對(duì)值進(jìn)行轉(zhuǎn)換,程序如下:
這個(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)換方法如下:
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; }
}