java Beanutils.copyProperties( )用法詳解
這是一篇開發(fā)自辯甩鍋稿~~~~
昨天測試小姐姐將我的一個bug單重開了,emmmm....內(nèi)心OS:就調(diào)整下對象某個屬性類型這么簡單的操作,我怎么可能會出錯呢,一定不是我的鍋??!but再怎么抗拒,bug還是要改的,畢竟晚上就要發(fā)版本了~~
老老實實將我前天改的部分跟了一遍,恩,完美,沒有任何的缺失~~but本應(yīng)success的測試數(shù)據(jù),接口返還的結(jié)果確實是false來著,那還是老老實實debug吧。
一步步跟下來,恩,多么順暢,就說一定不是我的鍋~~誒?不對不對,這里的ID值,為啥是null?傳過來有值的呀??!發(fā)現(xiàn)原來是別人在修復(fù)bug時用了Beanutils.copyProperties( obj1,obj2),but 因為obj1中屬性名稱id,obj2中屬性名稱afterId,因為Beanutils.copyProperties( )要求處理的兩個對象的屬性名稱相同時才可以正常賦值,那好吧,我們今天就好好講講關(guān)于Beanutils.copyProperties( )吧~
1、簡介
BeanUtils提供對Java反射和自省API的包裝。其主要目的是利用反射機(jī)制對JavaBean的屬性進(jìn)行處理。
2、用法
如果有兩個具有很多相同屬性的JavaBean,一個很常見的情況就是Struts里的PO對象(持久對象)和對應(yīng)的ActionForm。例如:一個用戶注冊頁面,有一個User實體類和一個UserActionForm實體類,我們一般會在Action里從ActionForm構(gòu)造一個PO對象,傳統(tǒng)的方式是使用類似下面的語句對屬性逐個賦值:
// 獲取 ActionForm 表單數(shù)據(jù) UserActionForm uForm = (UserActionForm) form; // 構(gòu)造一個User對象 User user = new User(); // 逐一賦值 user.setUsername(uForm.getUsername); user.setPassword(uForm.getPassword); user.setAge(uForm.getAge); ........... ........... // 然后調(diào)用JDBC、或操作Hibernate 持久化對象User到數(shù)據(jù)庫 ...
通過這樣的方法如果表單屬性字段很多,達(dá)到了100、1000甚至更多,那我們不是要寫100、1000行set、get了。誰都不愿意這樣做。
而我們使用 BeanUtils.copyProperties() 方法以后,代碼量大大的減少,而且整體程序看著也簡潔明朗,代碼如下:
// 獲取 ActionForm 表單數(shù)據(jù) UserActionForm uForm = (UserActionForm) form; // 構(gòu)造一個User對象 User user = new User(); // 賦值 BeanUtils.copyProperties(user, uForm); // 然后調(diào)用JDBC、或操作Hibernate 持久化對象User到數(shù)據(jù)庫 .......
注:如果User和UserActionForm 間存在名稱不相同的屬性,則BeanUtils不對這些屬性進(jìn)行處理,需要手動處理。例如:
User類里面有個createDate 創(chuàng)建時間字段,而UserActionForm里面無此字段。BeanUtils.copyProperties()不會對此字段做任何處理。必須要自己手動處理。
用法總結(jié)如下:
[java] view plain copy print? BeanUtils.copyProperties("要轉(zhuǎn)換的類", "轉(zhuǎn)換后的類"); [java] view plain copy print? PropertyUtils.copyProperties("要轉(zhuǎn)換的類", "轉(zhuǎn)換后的類");
用法其實很簡單,第一個參數(shù)是要轉(zhuǎn)換的類,第二個參數(shù)是轉(zhuǎn)換后的類。
BeanUtils.copyProperties VS PropertyUtils.copyProperties
兩者最大的區(qū)別是:
BeanUtils.copyProperties會進(jìn)行類型轉(zhuǎn)換,而PropertyUtils.copyProperties不會。
既然進(jìn)行了類型轉(zhuǎn)換,那BeanUtils.copyProperties的速度比不上PropertyUtils.copyProperties。
因此,PropertyUtils.copyProperties應(yīng)用的范圍稍為窄一點,它只對名字和類型都一樣的屬性進(jìn)行copy,如果名字一樣但類型不一樣,它會報錯。
使用BeanUtils有幾個要注意的地方:
1.對于類型為Boolean/Short/Integer/Float/Double的屬性,它會轉(zhuǎn)換為0:
public class User { private Integer intVal; private Double doubleVal; private Short shortVal; private Long longVal; private Float floatVal; private Byte byteVal; private Boolean booleanVal; } User src = new User(); User dest = new User(); BeanUtils.copyProperties(dest, src); System.out.println(src); System.out.println(dest); //輸出 User [intVal=null, doubleVal=null, shortVal=null, longVal=null, floatVal=null, byteVal=null, booleanVal=null] User [intVal=0, doubleVal=0.0, shortVal=0, longVal=0, floatVal=0.0, byteVal=0, booleanVal=false]
在stackoverflow上有人解釋說是因為這幾個類型都有對應(yīng)的基本類型,在進(jìn)行類型轉(zhuǎn)換時,有可能遇到類似Integer -> int的轉(zhuǎn)換,此時顯然不能對int類型的屬性賦值為null,因此統(tǒng)一轉(zhuǎn)換為0。
如何讓它不要轉(zhuǎn)為0呢?可以這樣:
import org.apache.commons.beanutils.converters.IntegerConverter; IntegerConverter converter = new IntegerConverter(null); //默認(rèn)為null,而不是0 BeanUtilsBean beanUtilsBean = new BeanUtilsBean(); beanUtilsBean.getConvertUtils().register(converter, Integer.class);
2.對于java.util.Date/BigDecimal/java.sql.Date/java.sql.Timestamp/java.sql.Time這幾個類,如果值為null,則在copy時會拋異常,需要使用對應(yīng)的Conveter:
public class User2 { private java.util.Date javaUtilDateVal; private java.sql.Date javaSqlDateVal; private java.sql.Timestamp javaSqlTimeStampVal; private BigDecimal bigDecimalVal; private java.sql.Time javaSqlTime; } User2 src = new User2(); User2 dest = new User2(); BeanUtilsBean beanUtilsBean = new BeanUtilsBean(); //如果沒有下面幾行,則在轉(zhuǎn)換null時會拋異常,例如:org.apache.commons.beanutils.ConversionException: No value specified for 'BigDecimal' //在org.apache.commons.beanutils.converters這個包下面有很多的Converter,可以按需要使用 beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.BigDecimalConverter(null), BigDecimal.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.DateConverter(null), java.util.Date.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.SqlTimestampConverter(null), java.sql.Timestamp.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.SqlDateConverter(null), java.sql.Date.class); beanUtilsBean.getConvertUtils().register(new org.apache.commons.beanutils.converters.SqlTimeConverter(null), java.sql.Time.class); beanUtilsBean.copyProperties(dest, src); System.out.println(src); System.out.println(dest);
使用BeanUtils還會經(jīng)常碰到這樣變態(tài)的需求:
假設(shè)是從A復(fù)制到B:
需求1:如果B中某字段有值(不為null),則該字段不復(fù)制;也就是B中該字段沒值時,才進(jìn)行復(fù)制,適合于對B進(jìn)行補(bǔ)充值的情況。
需求2:如果A中某字段沒值(為null),則該字段不復(fù)制,也就是不要把null復(fù)制到B當(dāng)中。
對于需求1,可以這樣:
import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.PropertyUtils; public class CopyWhenNullBeanUtilsBean extends BeanUtilsBean{ @Override public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { try { Object destValue = PropertyUtils.getSimpleProperty(bean, name); if (destValue == null) { super.copyProperty(bean, name, value); } } catch (NoSuchMethodException e) { throw new RuntimeException(e); } } }
對于需求2,可以這樣:
import org.apache.commons.beanutils.BeanUtilsBean; public class CopyFromNotNullBeanUtilsBean extends BeanUtilsBean { @Override public void copyProperty(Object bean, String name, Object value) throws IllegalAccessException, InvocationTargetException { if (value == null) { return; } super.copyProperty(bean, name, value); } }
到此這篇關(guān)于java Beanutils.copyProperties( )用法詳解的文章就介紹到這了,更多相關(guān)java Beanutils.copyProperties 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
spring boot整合scurity做簡單的登錄校驗的實現(xiàn)
這篇文章主要介紹了spring boot整合scurity做簡單的登錄校驗的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Java多線程Thread , Future , Callable ,
本文主要介紹了Java多線程Thread , Future , Callable , FutureTask的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03java利用Future實現(xiàn)多線程執(zhí)行與結(jié)果聚合實例代碼
這篇文章主要給大家介紹了關(guān)于java利用Future實現(xiàn)多線程執(zhí)行與結(jié)果聚合的相關(guān)資料,Future模式的核心,去除了主函數(shù)的等待時間,并使得原本需要等待的時間段可以用于處理其他業(yè)務(wù)邏輯,需要的朋友可以參考下2021-12-12IntelliJ IDEA中如何調(diào)試Java Stream操作
這篇文章主要介紹了IntelliJ IDEA中如何優(yōu)雅的調(diào)試Java Stream操作,在強(qiáng)大的IDEA插件支持下,stream的調(diào)試其實也沒那么難了,下面就來學(xué)習(xí)一下在IDEA中如何調(diào)試stream操作吧2022-05-05Spring 定時任務(wù)@Scheduled 注解中的 Cron 表達(dá)式詳解
Cron 表達(dá)式是一種用于定義定時任務(wù)觸發(fā)時間的字符串表示形式,它由七個字段組成,分別表示秒、分鐘、小時、日期、月份、星期和年份,這篇文章主要介紹了Spring 定時任務(wù)@Scheduled 注解中的 Cron 表達(dá)式,需要的朋友可以參考下2023-07-07