摘要:拷貝操作又一個(gè)非常好用的工具類和中分別存在一個(gè),提供了對(duì)。除了支持基本類型以及基本類型的數(shù)組之外,還支持這些類的對(duì)象,其余一概不支持。而且,由于這些類都是采用反射機(jī)制實(shí)現(xiàn)的,對(duì)程序的效率也會(huì)有影響。因此,慎用或者使用看效果如何
java bean拷貝操作又一個(gè)非常好用的工具類 BeanUitls :
spring (org.springframework.beans.BeanUtils)和apache commons-beanutils(org.apache.commons.beanutils.BeanUtils)中分別存在一個(gè)BeanUtils,提供了對(duì)。
特別注意 這兩個(gè)類在不同的包下面,而這兩個(gè)類的copyProperties()方法里面?zhèn)鬟f的參數(shù)賦值是相反的。
例如:
a,b為對(duì)象
BeanUtils.copyProperties(a, b);
BeanUtils是org.springframework.beans.BeanUtils,
a拷貝到b
BeanUtils是org.apache.commons.beanutils.BeanUtils,
b拷貝到a
之前在寫程序時(shí),用到了兩個(gè)不同類型但屬性基本相同的對(duì)象的拷貝,由于類型不同源bean里屬性(Integer 向 int 拷貝)其值為null,這時(shí)會(huì)拋異常。
/** * 測(cè)試 spring 中的 bean 拷貝 * @throws Exception */ @org.junit.Test public void testBeanCopy() throws Exception { PersonEntity pe = new PersonEntity(); pe.setAge(1); //pe.setId(1234); // id 為 Integer 此時(shí)為null pe.setName("kevin"); Person person = new Person(); // Person 中的id為int類型 BeanUtils.copyProperties(pe, person); System.out.println(person); }
一個(gè)看似簡(jiǎn)單的問題困擾了在當(dāng)時(shí),于是抽空看了一下spring和apache commons-beanutils包中BeanUtils.copyProperties的實(shí)現(xiàn)。
spring中實(shí)現(xiàn)的方式很簡(jiǎn)單,就是對(duì)兩個(gè)對(duì)象中相同名字的屬性進(jìn)行簡(jiǎn)單get/set,僅檢查屬性的可訪問性。
源碼
package org.springframework.beans; private static void copyProperties(Object source, Object target, Class> editable, 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); ListignoreList = (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); } } } } } }
而commons-beanutils則施加了很多的檢驗(yàn),包括類型的轉(zhuǎn)換,甚至于還會(huì)檢驗(yàn)對(duì)象所屬的類的可訪問性。
源碼
package org.apache.commons.beanutils; public void copyProperties(Object dest, 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) { DynaProperty origDescriptors[] = ((DynaBean) orig).getDynaClass().getDynaProperties(); for (int i = 0; i < origDescriptors.length; i++) { String name = origDescriptors[i].getName(); if (getPropertyUtils().isWriteable(dest, name)) { Object value = ((DynaBean) orig).get(name); copyProperty(dest, name, value); } } } else if (orig instanceof Map) { Iterator names = ((Map) orig).keySet().iterator(); while (names.hasNext()) { String name = (String) names.next(); if (getPropertyUtils().isWriteable(dest, name)) { Object value = ((Map) orig).get(name); copyProperty(dest, name, value); } } } else /* if (orig is a standard JavaBean) */ { PropertyDescriptor origDescriptors[] = getPropertyUtils().getPropertyDescriptors(orig); for (int i = 0; i < origDescriptors.length; i++) { String name = origDescriptors[i].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 { Object value = getPropertyUtils().getSimpleProperty(orig, name); copyProperty(dest, name, value); } catch (NoSuchMethodException e) { ; // Should not happen } } } } }
而且,commons-beanutils中的裝換是不支持java.util.Date的。除了支持基本類型以及基本類型的數(shù)組之外,還支持java.sql.Date, java.sql.Time, java.sql.TimeStamp, java.io.File, javaio.URL這些類的對(duì)象,其余一概不支持。不過你可以自定義你的類的Converter。然后注冊(cè)進(jìn)去。所以在使用時(shí)
感覺commons-beanutils包中的這個(gè)BeanUtils類的copyProperties方法,太過復(fù)雜,約束太多,而且使用不便,雖然可擴(kuò)展性好了,但是易用性不高。
總結(jié):
關(guān)于bean復(fù)制,如果屬性較少,建議直接寫個(gè)方法完成get/set即可。如果屬性較多,可以自己采用反射實(shí)現(xiàn)一個(gè)滿足自己需要的工具類,或者使用spring的那個(gè)beanutils類,不建議使用commons-beanutils包中的那個(gè)BeanUtils類,剛看了下,這個(gè)類對(duì)于內(nèi)部靜態(tài)類的對(duì)象復(fù)制也會(huì)出現(xiàn)問題,檢驗(yàn)太復(fù)雜了,常會(huì)出現(xiàn)一些詭異的問題。畢竟我們bean復(fù)制一般就是簡(jiǎn)單的屬性copy而已。
而且,由于這些BeanUtils類都是采用反射機(jī)制實(shí)現(xiàn)的,對(duì)程序的效率也會(huì)有影響。因此,慎用BeanUtils.copyProperties?。。』蛘呤褂胏lone看效果如何!
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/35799.html
摘要:從而能夠進(jìn)一步深入了解框架。至此我們框架開發(fā)完成。雖然說閱讀源碼是了解框架的最終手段。但是框架作為一個(gè)生產(chǎn)框架,為了保證通用和穩(wěn)定,源碼必定是高度抽象,且處理大量細(xì)節(jié)。下一篇文章應(yīng)該會(huì)是徒手?jǐn)]框架實(shí)現(xiàn)。 原文地址:https://www.xilidou.com/2018/... Spring 作為 J2ee 開發(fā)事實(shí)上的標(biāo)準(zhǔn),是每個(gè)Java開發(fā)人員都需要了解的框架。但是Spring 的...
1. BeanUtils.copyProperties(Object source, Object target) 用法: 講source的屬性值復(fù)制到target,屬性為null時(shí)也會(huì)進(jìn)行復(fù)制。 需求:排除null值進(jìn)行復(fù)制 public class CopyObjectUtil { public static String[] getNullPropertyNames(Object...
摘要:于是我建議這位小伙伴使用了進(jìn)行屬性拷貝,這為我們的程序挖了一個(gè)坑阿里代碼規(guī)約當(dāng)我們開啟阿里代碼掃描插件時(shí),如果你使用了進(jìn)行屬性拷貝,它會(huì)給你一個(gè)非常嚴(yán)重的警告。大名鼎鼎的提供的包,居然會(huì)存在性能問題,以致于阿里給出了嚴(yán)重的警告。 聲明:本文屬原創(chuàng)文章,始發(fā)于公號(hào):程序員自學(xué)之道,并同步發(fā)布于 https://blog.csdn.net/dadiyang,特此,同步發(fā)布到 sf,轉(zhuǎn)載請(qǐng)注...
摘要:解決鏈路間參數(shù)傳遞的問題可以簡(jiǎn)化為解決接口間的參數(shù)傳遞問題。當(dāng)然,針對(duì)這個(gè)問題的解決方案,其實(shí)還是蠻多的。總結(jié)下來,自動(dòng)化用例的維護(hù)和開發(fā)成本主要集中在接口間參數(shù)傳遞的維護(hù)上面。 引言 做過接口自動(dòng)化測(cè)試的同學(xué)肯定都熟悉在全鏈路測(cè)試過程中,很多業(yè)務(wù)場(chǎng)景的完成并非由單一接口實(shí)現(xiàn),而是由很多接...
摘要:背景許多時(shí)候需要對(duì)比不同的框架或工具或算法,選擇使用性能更優(yōu)的那一個(gè)。通常的做法是但這樣的做法非常不嚴(yán)謹(jǐn),因?yàn)楫?dāng)獨(dú)立頻繁運(yùn)行這一小塊代碼時(shí),可能會(huì)針對(duì)性的做一些優(yōu)化工作,而在實(shí)際的生產(chǎn)環(huán)境中是不會(huì)有此優(yōu)化的。 背景 許多時(shí)候需要對(duì)比不同的框架或工具或算法, 選擇使用性能更優(yōu)的那一個(gè)。通常的做法是 long start = System.currentTimeMillis(); for(...
閱讀 2855·2023-04-25 17:59
閱讀 685·2023-04-25 15:05
閱讀 675·2021-11-25 09:43
閱讀 3037·2021-10-12 10:13
閱讀 3545·2021-09-27 13:59
閱讀 3589·2021-09-23 11:21
閱讀 3888·2021-09-08 09:35
閱讀 571·2019-08-29 17:12