初用apache.commons.beanutils.BeanUtils
轉貼
fy198392
2005-11-25 11:23:59
查看評論 引言
該class提供了一系列的靜態(tài)方法操作業(yè)已存在的符合JavaBean規范定義的Java Class.這里強調的JavaBean規范,簡(jiǎn)單來(lái)說(shuō)就是一個(gè)Java Class通過(guò)一系列g(shù)etter和setter的方法向外界展示其內在的成員變量(屬性).通過(guò)BeanUtils的靜態(tài)方法,我們可以:
復制一個(gè)JavaBean的實(shí)例--BeanUtils.cloneBean(); 在一個(gè)JavaBean的兩個(gè)實(shí)例之間復制屬性--BeanUtils.copyProperties(),BeanUtils.copyProperty(); 為一個(gè)JavaBean的實(shí)例設置成員變量(屬性)值--BeanUtils.populate(),BeanUtils.setProperty(); 從一個(gè)一個(gè)JavaBean的實(shí)例中讀取成員變量(屬性)的值--BeanUtils.getArrayProperty(),BeanUtils.getIndexedProperty(),BeanUtils.getMappedProperty(),BeanUtils.getNestedProperty(),BeanUtils.getSimpleProperty(),BeanUtils.getProperty(),BeanUtils.describe();
總的來(lái)看BeanUtils類(lèi)提供了兩大類(lèi)的功能:讀,寫(xiě)成員變量.
準備工作
下面逐一分析使用方法.首先我們建立兩個(gè)JavaBean,名位SampleObject和SampleObjectA,具體如下:
package beanutil;
import java.util.HashMap;
import java.util.Map;
/**
* @author samepoint
*
* SampleObject contains some types of member varaibles:String,int,Array,Map,Object(self defined),just for test usaged of apache.commons.beanutils.BeanUtils
*/
public class SampleObject {
String name = null;
String display = null;
int num = -1;
char[] words = {‘a(chǎn)‘,‘b‘,‘c‘,‘d‘};
boolean tag = false;
Map map = new HashMap();
SampleObjectA sample = null;
/**
* default constructor. initialized members of map and sample.
*/
public SampleObject() {
this.map.put("home","localhost");
this.map.put("port","80");
}
//the following is getters and setters
/**
* @return Returns the display.
*/
public String getDisplay() {
return display;
}
/**
* @param display The display to set.
*/
public void setDisplay(String display) {
this.display = display;
}
/**
* @return Returns the name.
*/
public String getName() {
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name) {
this.name = name;
}
/**
* @return Returns the num.
*/
public int getNum() {
return num;
}
/**
* @param num The num to set.
*/
public void setNum(int num) {
this.num = num;
}
/**
* @return Returns the words.
*/
public char[] getWords() {
return words;
}
/**
* @param words The words to set.
*/
public void setWords(char[] words) {
this.words = words;
}
/**
* @return Returns the tag.
*/
public boolean isTag() {
return tag;
}
/**
* @param tag The tag to set.
*/
public void setTag(boolean tag) {
this.tag = tag;
}
/**
* @return Returns the map.
*/
public Map getMap() {
return map;
}
/**
* @param map The map to set.
*/
public void setMap(Map map) {
this.map = map;
}
/**
* @return Returns the sample.
*/
public SampleObject getSample() {
return sample;
}
/**
* @param sample The sample to set.
*/
public void setSample(SampleObject sample) {
this.sample = sample;
}
}
package beanutil;
/**
* @author samepoint
*
* Used to copy properties from SampleOjbect.
* Used to nested property.
*/
public class SampleObjectA {
String name = null;
String display = null;
Double num = null;
/**
* @return Returns the num.
*/
public Double getNum() {
return num;
}
/**
* @param num The num to set.
*/
public void setNum(Double num) {
this.num = num;
}
/**
* @return Returns the display.
*/
public String getDisplay() {
return display;
}
/**
* @param display The display to set.
*/
public void setDisplay(String display) {
this.display = display;
}
/**
* @return Returns the name.
*/
public String getName() {
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name) {
this.name = name;
}
}
所有測試使用的bean,如果未有說(shuō)明,均使用SampleObject.
所有測試使用的bean,如果未有說(shuō)明,均使用SampleObject. BeanUtils.cloneBean(java.lang.object bean)
為bean創(chuàng )建一個(gè)clone對象,方法返回類(lèi)型為Object.注意bean即使沒(méi)有實(shí)現java.lang.Cloneable接口,此方法依然有效.此方法的實(shí)現機制建立在bean提供的一系列的getters和setters的基礎之上.此方法的正常使用代碼非常簡(jiǎn)單,故略掉.
下面討論下如果bean沒(méi)有提供getters和setters,會(huì )出現什么情況,很明顯如果將其中的一對getter和setter注釋掉,如getDisplay()和setDisplay(),那么結果是根本不會(huì )針對display這個(gè)成員變量進(jìn)行復制;另外,如果將setDisplay()的訪(fǎng)問(wèn)限定符號設置為private的話(huà),結果也是一樣的,成員變量-display在clone的過(guò)程中不會(huì )被復制.注意上面討論的兩種情況,在運行時(shí)不會(huì )拋出任何的exception.對于不拋出exception的問(wèn)題,我也感到非常迷惑,因為此方法的javadoc上明明指出當不能訪(fǎng)問(wèn)bean上的accessor或不存在accessor時(shí),應該拋出java.lang.IllegalAccessException或java.lang.NotSuchMethodException.為了再次確認,我將SampleObject中的所有g(shù)etter和setter都注釋掉了,結果依然一樣,看來(lái)要看下源碼了.
BeanUtils.copyProperties(java.lang.Object dest, java.lang.Object orig)
一個(gè)bean class有兩個(gè)實(shí)例:orig和dest,將orig中的成員變量的值復制給dest,即將已經(jīng)存在的dest變?yōu)閛rig的副本.與BeanUtils.cloneBean(java.lang.object bean)的區別就在于是不是需要創(chuàng )建新的實(shí)例了.同樣正常使用代碼非常簡(jiǎn)單,這里也略掉.
如果bean class中沒(méi)有提供或是不完全提供getters和setters,結果如同在BeanUtils.cloneBean(java.lang.object bean)部分中的討論結果一樣.
另外,我曾經(jīng)這樣想,如果有兩個(gè)bean class,他們之間沒(méi)有任何關(guān)系,只是在成員變量的命名上有重疊(以SampleObject為例,如果我們有另外的bean class--AnotherSampleObject,也包含了成員變量display,name和num),他們之間是否可以利用BeanUtils.copyProperties(java.lang.Object dest, java.lang.Object orig)進(jìn)行復制呢?(這個(gè)想法來(lái)自于<struts in action>中formBean章節中關(guān)于formBean與valueObject的討論)答案是可以的,該方法會(huì )復制名稱(chēng)完全一樣的成員變量,即使成員變量的類(lèi)型不同也會(huì )自動(dòng)進(jìn)行轉換的(我在A(yíng)notherSampleObject中將num的類(lèi)型定義為Double,而SampleObject中的num為int),感覺(jué)真的是很神奇.回頭再去看看javadoc,發(fā)現這個(gè)方法原本就是如此設計的,原文如下:
Copy property values from the origin bean to the destination bean for all cases where the property names are the same.
其中for all cases where the property names are the same正是很好的明證,以后可以放心大膽的使用了.
ps:又對javadoc的重要性進(jìn)行重新認識,同時(shí)認識到自己的英文是那么的爛.
BeanUtils.copyProperty(java.lang.Object bean,java.lang.String name,java.lang.Object value)
這個(gè)方法簡(jiǎn)單的說(shuō)就是將bean中的成員變量name賦值為value.使用方法如下:
SampleObject sample = new SampleObject();
BeanUtils.copyProperty(sample,"num",new Integer(10));
如果成員變量為數組,如何為數據內的成員賦值呢?apache的java doc上說(shuō)的很明白,就是要提供一個(gè)包含索引參數的setter,所以要將以下代碼加到SampleObject的源代碼中.
/**
* set word with against
* @param index
* @param word
*/
public void setWords(int index,char word){
this.words[index] = word;
}
如果我們要為SampleObject中的words[2]賦值為S,那么代碼如下:
BeanUtils.copyProperty(a,"words[2]","S");
如果成員變量為Map,如何為Map內指定key賦值呢?同上面講的數組的方式一樣,就是要提供一個(gè)包含key參數的setter,在SampleObject中添加如下代碼:
/**
* set map with key
* @param key
* @param value
*/
public void setMap(Object key,Object value){
this.map.put(key,value);
}
如果我們要將SampleObject.map中home對應值改為remote,那么代碼如下:
BeanUtils.copyProperty(a,"map(home)","remote");
最后說(shuō)下如何為嵌套屬性的賦值,(所謂嵌套屬性就是beanA中一個(gè)成員變量是另外一個(gè)beanB,那么beanB中的屬性就叫做beanA的嵌套屬性了.),用法如下:
BeanUtils.copyProperty(a,"sample.display","second one");
BeanUtils.setProperty(java.lang.Object bean,java.lang.String name,java.lang.Object value)
這個(gè)方法讓我郁悶了一會(huì ),因為它提供的功能與上面說(shuō)的BeanUtils.copyProperty(java.lang.Object bean,java.lang.String name,java.lang.Object value)完全一致,apache的hero們沒(méi)理由為同一功能提供兩種展示方法啊,后來(lái)我看了apache.commons.beanutils.BeanUtilsBean中的javadoc,才明白了一點(diǎn)點(diǎn).如果我們只是為bean的屬性賦值的話(huà),使用copyProperty()就可以了;而setProperty()方法是實(shí)現BeanUtils.populate()(后面會(huì )說(shuō)到)機制的基礎,也就是說(shuō)如果我們需要自定義實(shí)現populate()方法,那么我們可以override setProperty()方法.
所以,做為一般的日常使用,setProperty()方法是不推薦使用的.
BeanUtils.populate(java.lang.Object bean, java.util.Map properties)
使用一個(gè)map為bean賦值,該map中的key的名稱(chēng)與bean中的成員變量名稱(chēng)相對應.注意:只有在key和成員變量名稱(chēng)完全對應的時(shí)候,populate機制才發(fā)生作用;但是在數量上沒(méi)有任何要求,如map中的key如果是成員變量名稱(chēng)的子集,那么成員變量中有的而map中不包含的項將會(huì )保留默認值;同樣,如果成員變量是map中key的子集,那么多余的key不會(huì )對populate的結果產(chǎn)生任何影響.恩,結果就是populate只針對map中key名稱(chēng)集合與bean中成員變量名稱(chēng)集合的交集產(chǎn)生作用.(很饒口啊)
正常用法很簡(jiǎn)單,這里略掉.
同樣,這個(gè)方法也支持對數組中單個(gè)元素,map中單個(gè)元素和嵌套屬性的賦值,具體做法和copyProperty()方法類(lèi)似,具體如下:
values.put("words[1]","U");
values.put("map(home)","remote");
values.put("sample.display",new Double(5.0));
注意:apache的javadoc中,明確指明這個(gè)方法是為解析http請求參數特別定義和使用的,在正常的使用中不推薦使用.他們推薦使用BeanUtils.copyProperties()方法.(struts中的FormBean應該是用這個(gè)方法裝配的)
BeanUtils.getArrayProperty(java.lang.Object bean,java.lang.String name)
獲取bean中數組成員變量(屬性)的值.
沒(méi)什么好說(shuō)的,用法很簡(jiǎn)單,略.
還是要說(shuō)一句,如果我們指定的name不是數組類(lèi)型的成員變量,結果會(huì )如何?會(huì )不會(huì )拋出類(lèi)型錯誤的exception呢?回答是不會(huì ),仍然會(huì )返回一個(gè)String的數組,數組的第一項就是name對應的值(如果不是String類(lèi)型的話(huà),JVM會(huì )自動(dòng)的調用toString()方法的).
BeanUtils.getIndexedProperty(java.lang.Object bean,java.lang.String name)
BeanUtils.getIndexedProperty(java.lang.Object bean,java.lang.String name,int index)
這兩個(gè)方法都是獲取數組成員變量(屬性)中的單一元素值的方法.比如,我想得到SampleObject中words[1]的值,用法如下:
BeanUtils.getIndexedProperty(sampleOjbectInstance,"words[1]");
BeanUtils.getIndexedProperty(sampleOjbectInstance,"words",1);
BeanUtils.getMappedProperty(java.lang.Object bean,java.lang.String name)
BeanUtils.getMappedProperty(java.lang.Object bean,java.lang.String name,java.lang.String key)
這兩個(gè)方法是獲取map成員變量中單一元素值的方法,用法與getIndexedProperty()方法相似,如我想得到SampleObject中map中home對應的值,用法如下:
BeanUtils.getMappedProperty(sampleOjbectInstance,map(home));
BeanUtils.getMappedProperty(sampleOjbectInstance,map,"home");
BeanUtils.getNestedProperty(java.lang.Object bean,java.lang.String name)
獲取嵌套屬性值的方法,如我想得到SampleOjbect中成員變量sample中的display的值,用法如下:
BeanUtils.getNestedProperty(sampleOjbectInstance,"sample.display");
BeanUtils.getSimpleProperty(java.lang.Object bean, java.lang.String name)
BeanUtils.getProperty(java.lang.Object bean, java.lang.String name)
獲取屬性值的方法.api已經(jīng)很清楚了,我唯一的問(wèn)題是這個(gè)simple是什么意思.javadoc只是說(shuō)了getProperty()方法中的name參數可以為普通屬性名稱(chēng),數組屬性名稱(chēng)或嵌套屬性名稱(chēng)的一種,而getSimpleProperty()方法中的name參數應該為普通屬性名稱(chēng)了.我的想法是通過(guò)對方法簽名的不同,讓developers可以顯示區別對待普通屬性,數組屬性,map屬性和嵌套屬性.
ps:具體有何區別,看來(lái)要仔細看看源代碼了.
BeanUtils.describe(java.lang.Object bean)
將一個(gè)bean以map的形式展示.(這個(gè)方法和populate()是我夢(mèng)想中的雙手劍)
但是使用這個(gè)方法得到的結果有點(diǎn)令我失望,以SampleObject為例,代碼片段如下:
SampleObject a = new SampleObject();
a.setDisplay("first one");
a.setName("A");
a.setNum(5);
a.setWords("goto".toCharArray());
SampleObjectA b = new SampleObjectA();
b.setDisplay("nested property");
b.setNum(new Double(2.0));
b.setName("sampleA");
a.setSample(b);
try {
Map descMap = BeanUtils.describe(a);
System.out.println(descMap);
}
......
運行結果如下:
{num=5, display=first one, class=class beanutil.SampleObject, words=g, tag=false,
sample=beanutil.SampleObjectA@be2358, map={port=80, home=localhost}, name=A}
首先可以看出,除了輸出SampleObject中定義的key-value外,還會(huì )包含class=class beanutil.SampleObject這一項,我想這是為了通過(guò)獲得的map我們可以知道原來(lái)的bean的具體類(lèi)型; 其次,作為數組成員變量(屬性)的words,在map中只包含了首個(gè)元素,而map類(lèi)型的成員變量的輸出結果到是非常令人滿(mǎn)意.為什么明明長(cháng)度為4的words數組現在輸出只有一個(gè)字符呢,我又進(jìn)行了debug,并監控了words變量,發(fā)現在返回的descMap中,words對應的值的類(lèi)型為String,長(cháng)度為1.
ps:不知道是不是我使用錯誤,真不知道為什么會(huì )這樣. 最后,嵌套屬性不會(huì )逐一進(jìn)行輸出的,除非你override了toString()方法.
與apache.commons.beanutils.BeanUtilsBean的關(guān)系
apache.commons.beanutils.BeanUtils中每個(gè)方法是通過(guò)apache.commons.beanutils.BeanUtilsBean實(shí)現的,apache.commons.beanutils.BeanUtils中靜態(tài)方法功能是默認方法,也就是最基本和最普通的,如果需要更復雜的功能實(shí)現的話(huà),則需要使用apache.commons.beanutils.BeanUtilsBean中的方法.apache.commons.beanutils.BeanUtilsBean可以在不同的緩沖區內存在不同的實(shí)例,從而可以提供不同的服務(wù),主要是converter的不同.通過(guò)這個(gè)機制可以為不同的用戶(hù)提供本地化的支持(我想這個(gè)在internet application上經(jīng)常要用到吧).我想這也是為什么apache.commons.beanutils.BeanUtilsBean不是interface而是class的原因.
標簽:
初用apache.commons.beanutils.BeanUtils[發(fā)起辯論][收藏到我的網(wǎng)摘][推薦] |
[評論] |
[投訴] |
[打印]本文章被推薦到了0 個(gè)圈子點(diǎn)擊數: 4
評論數:
1本文章引用通告地址(TrackBack Ping URL)為:
http://blog.hexun.com/fy198392/trackback.aspx?articleid=1544118
本文章尚未被引用。
上一篇:
慈禧名號的來(lái)歷下一篇:
HIBERNATE - 符合Java習慣的關(guān)系數據庫持久化進(jìn)入該博客主頁(yè)fy198392[
發(fā)送私信]
[
加為好友]Re: 初用apache.commons.beanutils.BeanUtils [2005-11-25 11:39:01]
BeanUtils簡(jiǎn)讀本
一、簡(jiǎn)介:
BeanUtils提供對 Java反射和自省API的包裝。其主要目的是利用反射機制對JavaBean的屬性進(jìn)行處理。我們知道,一個(gè)JavaBean通常包含了大量的屬性,很多情況下,對JavaBean的處理導致大量get/set代碼堆積,增加了代碼長(cháng)度和閱讀代碼的難度。
二、用法:
BeanUtils是這個(gè)包里比較常用的一個(gè)工具類(lèi),這里只介紹它的copyProperties()方法。該方法定義如下:
public static void copyProperties(java.lang.Object dest,java.lang.Object orig) throws java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException
如果你有兩個(gè)具有很多相同屬性的JavaBean,一個(gè)很常見(jiàn)的情況就是Struts里的PO對象(持久對象)和對應的ActionForm,例如 Teacher和TeacherForm。我們一般會(huì )在A(yíng)ction里從ActionForm構造一個(gè)PO對象,傳統的方式是使用類(lèi)似下面的語(yǔ)句對屬性逐個(gè)賦值:
//得到TeacherFormTeacherForm teacherForm=(TeacherForm)form;//構造Teacher對象Teacher teacher=new Teacher();//賦值teacher.setName(teacherForm.getName());teacher.setAge(teacherForm.getAge());teacher.setGender(teacherForm.getGender());teacher.setMajor(teacherForm.getMajor());teacher.setDepartment(teacherForm.getDepartment());//持久化Teacher對象到數據庫HibernateDAO=;HibernateDAO.save(teacher);而使用BeanUtils后,代碼就大大改觀(guān)了,如下所示://得到TeacherFormTeacherForm teacherForm=(TeacherForm)form;//構造Teacher對象Teacher teacher=new Teacher();//賦值BeanUtils.copyProperties(teacher,teacherForm);//持久化Teacher對象到數據庫HibernateDAO=;HibernateDAO.save(teacher);
如果Teacher和TeacherForm間存在名稱(chēng)不相同的屬性,則BeanUtils不對這些屬性進(jìn)行處理,需要程序員手動(dòng)處理。例如 Teacher包含modifyDate(該屬性記錄最后修改日期,不需要用戶(hù)在界面中輸入)屬性而TeacherForm無(wú)此屬性,那么在上面代碼的 copyProperties()后還要加上一句:
teacher.setModifyDate(new Date());
怎么樣,很方便吧!除BeanUtils外還有一個(gè)名為PropertyUtils的工具類(lèi),它也提供copyProperties()方法,作用與BeanUtils的同名方法十分相似,主要的區別在于后者提供類(lèi)型轉換功能,即發(fā)現兩個(gè)JavaBean的同名屬性為不同類(lèi)型時(shí),在支持的數據類(lèi)型范圍內進(jìn)行轉換,而前者不支持這個(gè)功能,但是速度會(huì )更快一些。BeanUtils支持的轉換類(lèi)型如下:
* java.lang.BigDecimal * java.lang.BigInteger * boolean and java.lang.Boolean * byte and java.lang.Byte * char and java.lang.Character * java.lang.Class * double and java.lang.Double * float and java.lang.Float * int and java.lang.Integer * long and java.lang.Long * short and java.lang.Short * java.lang.String * java.sql.Date * java.sql.Time * java.sql.Timestamp
這里要注意一點(diǎn),java.util.Date是不被支持的,而它的子類(lèi)java.sql.Date是被支持的。因此如果對象包含時(shí)間類(lèi)型的屬性,且希望被轉換的時(shí)候,一定要使用java.sql.Date類(lèi)型。否則在轉換時(shí)會(huì )提示argument mistype異常。
三、優(yōu)缺點(diǎn):
Apache Jakarta Commons項目非常有用。我曾在許多不同的項目上或直接或間接地使用各種流行的commons組件。其中的一個(gè)強大的組件就是BeanUtils。我將說(shuō)明如何使用BeanUtils將local實(shí)體bean轉換為對應的value 對象:
BeanUtils.copyProperties(aValue, aLocal)
上面的代碼從aLocal對象復制屬性到aValue對象。它相當簡(jiǎn)單!它不管local(或對應的value)對象有多少個(gè)屬性,只管進(jìn)行復制。我們假設local對象有100個(gè)屬性。上面的代碼使我們可以無(wú)需鍵入至少100行的冗長(cháng)、容易出錯和反復的get和set方法調用。這太棒了!太強大了!太有用了!
現在,還有一個(gè)壞消息:使用BeanUtils的成本驚人地昂貴!我做了一個(gè)簡(jiǎn)單的測試,BeanUtils所花費的時(shí)間要超過(guò)取數據、將其復制到對應的 value對象(通過(guò)手動(dòng)調用get和set方法),以及通過(guò)串行化將其返回到遠程的客戶(hù)機的時(shí)間總和。所以要小心使用這種威力!