BeanUtils.copyProperties()所有的空值不复制问题

网友投稿 516 2022-07-23


目录BeanUtils.copyProperties()所有的空值不复制第一种情况第二种情况BeanUtils.copyProperties()的用法和注意点属性为null也会被复制,内部类不会复制过去注意点一注意点二

BeanUtils.copyProperties()所有的空值不复制

第一种情况

所有为空值的属性都不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 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) {

TopMenuConfigEnXWGtRtity 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());

}

}

执行main 方法后,topMenuConfigEntity1的title还是为原来的“animal”值,没有被topMenuConfigEntity2 的空值覆盖。

第二种情况

原对象的属性有值,复制时指定某些字段不复制

调BeanUtils的这个方法

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,没有复制

BeanUtils.copyProperties()的用法和注意点

属性为null也会被复制,内部类不会复制过去

BeanUtils提供对java反射和自省API的包装。其主要目的是利用反射机制对JavaBean的属性进行处理。我们知道,一个JavaBean通常包含了大量的属性,很多情况下,对JavaBean的处理导致大量get/set代码堆积,增加了代码长度和阅读代码的难度。

BeanUtils是这个包里比较常用的一个工具类,这里只介绍它的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 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);

}

}

}

}

}

}

如果你有两个具有很多相同属性的JavaBean,就可以试用该方法将sourse中的属性copy到target中,如果sourse和target间存在名称不相同的属性,则BeanUtils不对这些属性进行处理,需要程序员手动处理。

怎么样,很方便吧!除BeanUtils外还有一个名为PropertyUtils的工具类,它也提供copyProperties()方法,作用与 BeanUtils的同名方法十分相似,主要的区别在于后者提供类型转换功能,即发现两个JavaBean的同名属性为不同类型时,在支持的数据类型范围内进行转换,而前者不支持这个功能,但是速度会更快一些。

BeanUtils支持的转换类型如下:

* 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

这里要注意一点,java.util.Date是不被支持的,而它的子类java.sql.Date是被支持的。因此如果对象包含时间类型的属性,且希望被转换的时候,一定要使用java.sql.Date类型。否则在转换时会提示argument mistype异常。

现在,还有一个坏消息:使用BeanUtils的成本惊人地昂贵!我做了一个简单的测试,BeanUtils所花费的时间要超过取数 据、将其复制到对应的 value对象(通过手动调用get和set方法),以及通过串行化将其返回到远程的客户机的时间总和。所以要小心使用。

注意点一

apache和spring的工具包中都有BeanUtils,使用其中的copyProperties方法可以非常方便的进行这些工作,但在实际应用中发现,对于null的处理不太符合个人的需要,例如在进行修改操作中只需要对model中某一项进行修改,那么一般我们在页面上只提交model的ID及需要修改项的值,这个时候使用BeanUtils.copyProperties会将其他的null绑定到pojo中去。

大家可以直接调用我们加工类的copyPropertiesIgnoreNull()方法即可忽略null值,避免老数据被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 {

/**

* 当前IOC

*

*/

private static ApplicationContext applicationContext;

/**

* * 设置当前上下文环境,此方法由spring自动装配

*

*/

@Override

public void setApplicationContext(ApplicationContext arg0)

throws BeansException {

applicationContext = arg0;

}

/**

* 从当前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.getPropertyhttp://Descriptors();

Set emptyNames = new HashSet();

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));

}

}

调用:copyPropertiesIgnoreNull

public class TestBeanUtiles {

public static void main(String[] args) {

NewPerson newPerson = new NewPerson();

newPerson.setName("bifuguo");//前台用户更新过的数据,例如前台只修改了用户名

//下面我们假设是从数据库加载出来的老数据

OldPerson oldPerson = new OldPerson();

oldPerson.setSex("nv");

oldPerson.setAge(5);

//如果我们想把新数据更新到老数据这个对象里面,我们就可以借助BeanUtils.copyProperties()的方法如下:

//BeanUtils.copyProperties(newPerson, oldPerson);

SpringUtil.copyPropertiesIgnoreNull(newPerson, oldPerson);

System.out.println(newPerson.toString());

System.out.println(oldPerson.toString());

}

}

打印结果:

NewPerson{name='bifuguo', sex='null', age=0}OldPerson{name='bifuguo', sex='nv', age=0}

现在就可以看出老数据没有被null覆盖

注意点二

1.Spring的BeanUtils的CopyProperties方法需要对应的属性有getter和setter方法;

2.如果存在属性完全相同的内部类,但是不是同一个内部类,即分别属于各自的内部类,则spring会认为属性不同,不会copy;

3.泛型只在编译期起作用,不能依靠泛型来做运行期的限制;

4.最后,spring和apache的copy属性的方法源和目的参数的位置正好相反,所以导包和调用的时候都要注意一XWGtR下。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java多线程中Lock锁的使用小结
下一篇:一文搞懂Mybatis
相关文章

 发表评论

暂时没有评论,来抢沙发吧~