您好,登錄后才能下訂單哦!
本文小編為大家詳細(xì)介紹“BeanUtils.copyProperties()所有的空值不復(fù)制問題怎么解決”,內(nèi)容詳細(xì),步驟清晰,細(xì)節(jié)處理妥當(dāng),希望這篇“BeanUtils.copyProperties()所有的空值不復(fù)制問題怎么解決”文章能幫助大家解決疑惑,下面跟著小編的思路慢慢深入,一起來學(xué)習(xí)新知識吧。
所有為空值的屬性都不copy
直接上代碼吧~
public class UpdateUtil { /** * 所有為空值的屬性都不copy * * @param source * @param target */ public static void copyNullProperties(Object source, Object target) { BeanUtils.copyProperties(source, target, getNullField(source)); } /** * 獲取屬性中為空的字段 * * @param target * @return */ private static String[] getNullField(Object target) { BeanWrapper beanWrapper = new BeanWrapperImpl(target); PropertyDescriptor[] propertyDescriptors = beanWrapper.getPropertyDescriptors(); Set<String> notNullFieldSet = new HashSet<>(); if (propertyDescriptors.length > 0) { for (PropertyDescriptor p : propertyDescriptors) { String name = p.getName(); Object value = beanWrapper.getPropertyValue(name); if (Objects.isNull(value)) { notNullFieldSet.add(name); } } } String[] notNullField = new String[notNullFieldSet.size()]; return notNullFieldSet.toArray(notNullField); } public static void main(String[] args) { TopMenuConfigEntity topMenuConfigEntity1 = new TopMenuConfigEntity(); topMenuConfigEntity1.setWardCode("cat"); topMenuConfigEntity1.setTitle("animal"); TopMenuConfigEntity topMenuConfigEntity2 = new TopMenuConfigEntity(); topMenuConfigEntity2.setWardCode("dog"); UpdateUtil.copyNullProperties(topMenuConfigEntity2,topMenuConfigEntity1); System.out.println(topMenuConfigEntity1.getTitle()); } }
執(zhí)行main 方法后,topMenuConfigEntity1的title還是為原來的“animal”值,沒有被topMenuConfigEntity2 的空值覆蓋。
原對象的屬性有值,復(fù)制時(shí)指定某些字段不復(fù)制
調(diào)BeanUtils的這個(gè)方法
public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException { copyProperties(source, target, null, ignoreProperties); }
public static void main(String[] args) { TopMenuConfigEntity topMenuConfigEntity1 = new TopMenuConfigEntity(); topMenuConfigEntity1.setWardCode("cat"); topMenuConfigEntity1.setTitle("animal"); topMenuConfigEntity1.setCreateTime(new Date()); TopMenuConfigEntity topMenuConfigEntity2 = new TopMenuConfigEntity(); String[] ignoreArray = new String[]{"title","createTime"}; BeanUtils.copyProperties(topMenuConfigEntity2,topMenuConfigEntity1,ignoreArray); System.out.println("title : "+topMenuConfigEntity2.getTitle() +";createTime :" + topMenuConfigEntity2.getCreateTime()); }
topMenuConfigEntity2的title 和createTime為null,沒有復(fù)制
BeanUtils提供對Java反射和自省API的包裝。其主要目的是利用反射機(jī)制對JavaBean的屬性進(jìn)行處理。我們知道,一個(gè)JavaBean通常包含了大量的屬性,很多情況下,對JavaBean的處理導(dǎo)致大量get/set代碼堆積,增加了代碼長度和閱讀代碼的難度。
BeanUtils是這個(gè)包里比較常用的一個(gè)工具類,這里只介紹它的copyProperties()方法。
該方法源碼如下:
public static void copyProperties(Object source, Object target) throws BeansException { copyProperties(source, target, (Class)null, (String[])null); } public static void copyProperties(Object source, Object target, Class<?> editable) throws BeansException { copyProperties(source, target, editable, (String[])null); } public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException { copyProperties(source, target, (Class)null, ignoreProperties); } 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); List<String> ignoreList = ignoreProperties != null?Arrays.asList(ignoreProperties):null; PropertyDescriptor[] var7 = targetPds; int var8 = targetPds.length; for(int var9 = 0; var9 < var8; ++var9) { PropertyDescriptor targetPd = var7[var9]; 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, new Object[0]); if(!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, new Object[]{value}); } catch (Throwable var15) { throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var15); } } } } } }
如果你有兩個(gè)具有很多相同屬性的JavaBean,就可以試用該方法將sourse中的屬性copy到target中,如果sourse和target間存在名稱不相同的屬性,則BeanUtils不對這些屬性進(jìn)行處理,需要程序員手動(dòng)處理。
怎么樣,很方便吧!除BeanUtils外還有一個(gè)名為PropertyUtils的工具類,它也提供copyProperties()方法,作用與 BeanUtils的同名方法十分相似,主要的區(qū)別在于后者提供類型轉(zhuǎn)換功能,即發(fā)現(xiàn)兩個(gè)JavaBean的同名屬性為不同類型時(shí),在支持的數(shù)據(jù)類型范圍內(nèi)進(jìn)行轉(zhuǎn)換,而前者不支持這個(gè)功能,但是速度會更快一些。
BeanUtils支持的轉(zhuǎn)換類型如下:
* 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是不被支持的,而它的子類java.sql.Date是被支持的。因此如果對象包含時(shí)間類型的屬性,且希望被轉(zhuǎn)換的時(shí)候,一定要使用java.sql.Date類型。否則在轉(zhuǎn)換時(shí)會提示argument mistype異常。
現(xiàn)在,還有一個(gè)壞消息:使用BeanUtils的成本驚人地昂貴!我做了一個(gè)簡單的測試,BeanUtils所花費(fèi)的時(shí)間要超過取數(shù) 據(jù)、將其復(fù)制到對應(yīng)的 value對象(通過手動(dòng)調(diào)用get和set方法),以及通過串行化將其返回到遠(yuǎn)程的客戶機(jī)的時(shí)間總和。所以要小心使用。
apache和spring的工具包中都有BeanUtils,使用其中的copyProperties方法可以非常方便的進(jìn)行這些工作,但在實(shí)際應(yīng)用中發(fā)現(xiàn),對于null的處理不太符合個(gè)人的需要,例如在進(jìn)行修改操作中只需要對model中某一項(xiàng)進(jìn)行修改,那么一般我們在頁面上只提交model的ID及需要修改項(xiàng)的值,這個(gè)時(shí)候使用BeanUtils.copyProperties會將其他的null綁定到pojo中去。
大家可以直接調(diào)用我們加工類的copyPropertiesIgnoreNull()方法即可忽略null值,避免老數(shù)據(jù)被null覆蓋的尷尬。具體代碼如下:
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanWrapper; import org.springframework.beans.BeanWrapperImpl; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import java.util.HashSet; import java.util.Set; public class SpringUtil implements ApplicationContextAware { /** * 當(dāng)前IOC * */ private static ApplicationContext applicationContext; /** * * 設(shè)置當(dāng)前上下文環(huán)境,此方法由spring自動(dòng)裝配 * */ @Override public void setApplicationContext(ApplicationContext arg0) throws BeansException { applicationContext = arg0; } /** * 從當(dāng)前IOC獲取bean * * @param id * bean的id * @return * */ public static Object getObject(String id) { Object object = null; object = applicationContext.getBean(id); return object; } public static String[] getNullPropertyNames (Object source) { final BeanWrapper src = new BeanWrapperImpl(source); java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors(); Set<String> emptyNames = new HashSet<String>(); for(java.beans.PropertyDescriptor pd : pds) { Object srcValue = src.getPropertyValue(pd.getName()); if (srcValue == null) emptyNames.add(pd.getName()); } String[] result = new String[emptyNames.size()]; return emptyNames.toArray(result); } public static void copyPropertiesIgnoreNull(Object src, Object target){ BeanUtils.copyProperties(src, target, getNullPropertyNames(src)); } }
調(diào)用:copyPropertiesIgnoreNull
public class TestBeanUtiles { public static void main(String[] args) { NewPerson newPerson = new NewPerson(); newPerson.setName("bifuguo");//前臺用戶更新過的數(shù)據(jù),例如前臺只修改了用戶名 //下面我們假設(shè)是從數(shù)據(jù)庫加載出來的老數(shù)據(jù) OldPerson oldPerson = new OldPerson(); oldPerson.setSex("nv"); oldPerson.setAge(5); //如果我們想把新數(shù)據(jù)更新到老數(shù)據(jù)這個(gè)對象里面,我們就可以借助BeanUtils.copyProperties()的方法如下: //BeanUtils.copyProperties(newPerson, oldPerson); SpringUtil.copyPropertiesIgnoreNull(newPerson, oldPerson); System.out.println(newPerson.toString()); System.out.println(oldPerson.toString()); } }
打印結(jié)果:
NewPerson{name='bifuguo', sex='null', age=0}
OldPerson{name='bifuguo', sex='nv', age=0}
現(xiàn)在就可以看出老數(shù)據(jù)沒有被null覆蓋
1.Spring的BeanUtils的CopyProperties方法需要對應(yīng)的屬性有g(shù)etter和setter方法;
2.如果存在屬性完全相同的內(nèi)部類,但是不是同一個(gè)內(nèi)部類,即分別屬于各自的內(nèi)部類,則spring會認(rèn)為屬性不同,不會copy;
3.泛型只在編譯期起作用,不能依靠泛型來做運(yùn)行期的限制;
4.最后,spring和apache的copy屬性的方法源和目的參數(shù)的位置正好相反,所以導(dǎo)包和調(diào)用的時(shí)候都要注意一下。
讀到這里,這篇“BeanUtils.copyProperties()所有的空值不復(fù)制問題怎么解決”文章已經(jīng)介紹完畢,想要掌握這篇文章的知識點(diǎn)還需要大家自己動(dòng)手實(shí)踐使用過才能領(lǐng)會,如果想了解更多相關(guān)內(nèi)容的文章,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。