BeanUtils 是用 Spring 的還是 Apache 的好?

前言
get/set代碼,當(dāng)然這是我們開發(fā)過程不愿意去做的,因為它確實顯得很繁瑣。為了解決這一痛點,就誕生了一些方便的類庫,常用的有 apache的?BeanUtils,spring的?BeanUtils,?Dozer,Orika等拷貝工具。這篇文章主要介紹 Apache的BeanUtils 與 Spring 的BeanUtils,其他框架后續(xù)文章再做介紹對象拷貝
什么是淺拷貝和深拷貝
淺拷貝:對基本數(shù)據(jù)類型進(jìn)行值傳遞,對引用數(shù)據(jù)類型進(jìn)行引用傳遞般的拷貝,此為淺拷貝 深拷貝:對基本數(shù)據(jù)類型進(jìn)行值傳遞,對引用數(shù)據(jù)類型,創(chuàng)建一個新的對象,并復(fù)制其內(nèi)容,此為深拷貝。
BeanUtils
apache 的 BeanUtils
public?class?PersonSource??{
????private?Integer?id;
????private?String?username;
????private?String?password;
????private?Integer?age;
????//?getters/setters?omiited
}
public?class?PersonDest?{
????private?Integer?id;
????private?String?username;
????private?Integer?age;
????//?getters/setters?omiited
}
public?class?TestApacheBeanUtils?{
????public?static?void?main(String[]?args)?throws?InvocationTargetException,?IllegalAccessException?{
???????//下面只是用于單獨測試
????????PersonSource?personSource?=?new?PersonSource(1,?"pjmike",?"12345",?21);
????????PersonDest?personDest?=?new?PersonDest();
????????BeanUtils.copyProperties(personDest,personSource);
????????System.out.println("persondest:?"+personDest);
????}
}
persondest:?PersonDest{id=1,?username='pjmike',?age=21}
//將源對象中的值拷貝到目標(biāo)對象
public?static?void?copyProperties(Object?dest,?Object?orig)?throws?IllegalAccessException,?InvocationTargetException?{
????BeanUtilsBean.getInstance().copyProperties(dest,?orig);
}
org.apache.commons.beanutils.BeanUtils對復(fù)雜對象的復(fù)制是引用,這是一種淺拷貝public?void?copyProperties(final?Object?dest,?final?Object?orig)
????????throws?IllegalAccessException,?InvocationTargetException?{
????????//?Validate?existence?of?the?specified?beans
????????if?(dest?==?null)?{
????????????throw?new?IllegalArgumentException
????????????????????("No?destination?bean?specified");
????????}
????????if?(orig?==?null)?{
????????????throw?new?IllegalArgumentException("No?origin?bean?specified");
????????}
????????if?(log.isDebugEnabled())?{
????????????log.debug("BeanUtils.copyProperties("?+?dest?+?",?"?+
??????????????????????orig?+?")");
????????}
????????//?Copy?the?properties,?converting?as?necessary
????????if?(orig?instanceof?DynaBean)?{
????????????final?DynaProperty[]?origDescriptors?=
????????????????((DynaBean)?orig).getDynaClass().getDynaProperties();
????????????for?(DynaProperty?origDescriptor?:?origDescriptors)?{
????????????????final?String?name?=?origDescriptor.getName();
????????????????//?Need?to?check?isReadable()?for?WrapDynaBean
????????????????//?(see?Jira?issue#?BEANUTILS-61)
????????????????if?(getPropertyUtils().isReadable(orig,?name)?&&
????????????????????getPropertyUtils().isWriteable(dest,?name))?{
????????????????????final?Object?value?=?((DynaBean)?orig).get(name);
????????????????????copyProperty(dest,?name,?value);
????????????????}
????????????}
????????}?else?if?(orig?instanceof?Map)?{
????????????@SuppressWarnings("unchecked")
????????????final
????????????//?Map?properties?are?always?of?type?
????????????Map?propMap?=?(Map )?orig;
????????????for?(final?Map.Entry?entry?:?propMap.entrySet())?{
????????????????final?String?name?=?entry.getKey();
????????????????if?(getPropertyUtils().isWriteable(dest,?name))?{
????????????????????copyProperty(dest,?name,?entry.getValue());
????????????????}
????????????}
????????}?else?/*?if?(orig?is?a?standard?JavaBean)?*/?{
????????????final?PropertyDescriptor[]?origDescriptors?=
????????????????getPropertyUtils().getPropertyDescriptors(orig);
????????????for?(PropertyDescriptor?origDescriptor?:?origDescriptors)?{
????????????????final?String?name?=?origDescriptor.getName();
????????????????if?("class".equals(name))?{
????????????????????continue;?//?No?point?in?trying?to?set?an?object's?class
????????????????}
????????????????if?(getPropertyUtils().isReadable(orig,?name)?&&
????????????????????getPropertyUtils().isWriteable(dest,?name))?{
????????????????????try?{
????????????????????????final?Object?value?=
????????????????????????????getPropertyUtils().getSimpleProperty(orig,?name);
????????????????????????copyProperty(dest,?name,?value);
????????????????????}?catch?(final?NoSuchMethodException?e)?{
????????????????????????//?Should?not?happen
????????????????????}
????????????????}
????????????}
????????}
????}
spring的 BeanUtils
public?class?TestSpringBeanUtils?{
????public?static?void?main(String[]?args)?throws?InvocationTargetException,?IllegalAccessException?{
???????//下面只是用于單獨測試
????????PersonSource?personSource?=?new?PersonSource(1,?"pjmike",?"12345",?21);
????????PersonDest?personDest?=?new?PersonDest();
????????BeanUtils.copyProperties(personSource,personDest);
????????System.out.println("persondest:?"+personDest);
????}
}
copyProperties方法進(jìn)行拷貝,只不過它的實現(xiàn)方式非常簡單,就是對兩個對象中相同名字的屬性進(jìn)行簡單的get/set,僅檢查屬性的可訪問性。具體實現(xiàn)如下:private?static?void?copyProperties(Object?source,?Object?target,?@Nullable?Class>?editable,
???@Nullable?String...?ignoreProperties)?throws?BeansException?{
??Assert.notNull(source,?"Source?must?not?be?null");
??Assert.notNull(target,?"Target?must?not?be?null");
??Class>?actualEditable?=?target.getClass();
??if?(editable?!=?null)?{
???if?(!editable.isInstance(target))?{
????throw?new?IllegalArgumentException("Target?class?["?+?target.getClass().getName()?+
??????"]?not?assignable?to?Editable?class?["?+?editable.getName()?+?"]");
???}
???actualEditable?=?editable;
??}
??PropertyDescriptor[]?targetPds?=?getPropertyDescriptors(actualEditable);
??List?ignoreList?=?(ignoreProperties?!=?null???Arrays.asList(ignoreProperties)?:?null);
??for?(PropertyDescriptor?targetPd?:?targetPds)?{
???Method?writeMethod?=?targetPd.getWriteMethod();
???if?(writeMethod?!=?null?&&?(ignoreList?==?null?||?!ignoreList.contains(targetPd.getName())))?{
????PropertyDescriptor?sourcePd?=?getPropertyDescriptor(source.getClass(),?targetPd.getName());
????if?(sourcePd?!=?null)?{
?????Method?readMethod?=?sourcePd.getReadMethod();
?????if?(readMethod?!=?null?&&
???????ClassUtils.isAssignable(writeMethod.getParameterTypes()[0],?readMethod.getReturnType()))?{
??????try?{
???????if?(!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()))?{
????????readMethod.setAccessible(true);
???????}
???????Object?value?=?readMethod.invoke(source);
???????if?(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()))?{
????????writeMethod.setAccessible(true);
???????}
???????writeMethod.invoke(target,?value);
??????}
??????catch?(Throwable?ex)?{
???????throw?new?FatalBeanException(
?????????"Could?not?copy?property?'"?+?targetPd.getName()?+?"'?from?source?to?target",?ex);
??????}
?????}
????}
???}
??}
?}
小結(jié)
---END--- 重磅!碼農(nóng)突圍-技術(shù)交流群已成立 掃碼可添加碼農(nóng)突圍助手,可申請加入碼農(nóng)突圍大群和細(xì)分方向群,細(xì)分方向已涵蓋:Java、Python、機器學(xué)習(xí)、大數(shù)據(jù)、人工智能等群。 一定要備注:開發(fā)方向+地點+學(xué)校/公司+昵稱(如Java開發(fā)+上海+拼夕夕+猴子),根據(jù)格式備注,可更快被通過且邀請進(jìn)群 ▲長按加群 推薦閱讀
? ?面試:如何決定使用 HashMap 還是 TreeMap? ???2020中國高校薪資排行出爐!好過雙一流的高校原來這么多! ???還只是 39 歲!一個天才年輕程序員的隕落 ???認(rèn)真看看, 以后寫 SQL 就爽多了:MyBatis 動態(tài) SQL ?? 臥槽!微信居然有“隱身功能”了! ?? 滴滴十大技術(shù)方向開源項目出爐!有點牛?。?/a> 最近面試BAT,整理一份面試資料《Java面試BAT通關(guān)手冊》,覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫、數(shù)據(jù)結(jié)構(gòu)等等。
獲取方式:點“在看”,關(guān)注公眾號并回復(fù)?BAT?領(lǐng)取,更多內(nèi)容陸續(xù)奉上。
如有收獲,點個在看,誠摯感謝
明天見(??ω??)??
評論
圖片
表情

明天見(??ω??)??