关于BeanUtils拷贝null属性的问题

关于BeanUtils拷贝null属性的问题

jen wang

 

       帮同事查看物流发货问题时,发现BeanUtilscopy null属性时会有一些问题。现在总结一下现象、原因和解决方法。

问题现象

       1.当源对象(a)中存在一个java.sql.Date类型的属性并且值为null,目标对象(b)中也存在这个同名同类型的属性。把a对象属性值copybBeanUtils.copyProperties(b, a);会抛出异常;

       2.当源对象(a)中存在一个java.sql.Date类型的属性并且值为null,目标对象(b)不存在这个同名同类型的属性,copy时没问题。

原因

       查看BeanUtils源代码,定位到org.apache.commons.beanutils.BeanUtilsBean.copyProperties(Object dest, Object orig)方法的关键代码,

 

public void copyProperties(Object dest, Object orig)

        throws IllegalAccessException, InvocationTargetException {

   

    ……

    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

           }

    }

    ……

}

 

isWriteable这一行,当目标对象没有相应的属性时不进行copy,所以不会有问题(现象2)

再看copyProperty方法的关键代码,



 

引起现象1的代码为value = converter.convert(type, value);这行,这里会抛出一个类型转换错误。转化器在转化时报错,需要找出这个转化器,继续往下看代码,ConvertUtilsBean.lookup(Class clazz)方法,



 

再看converters中注册的转化器方法ConvertUtilsBean.deregister()的关键代码,



 
 

找到了相应的转化器SqlDateConverter,异常就在这个SqlDateConverter转化类型时抛出,当java.sql.Date类型的属性值为null时抛异常。



 

解决方法

<!--[if !supportLists]-->l  <!--[endif]-->方法一

       convert方法可以看出只要想办法把useDefaultdefaultValue设值就能解决,SqlDateConverter的另外一个构造方法可以设置这两个值,问题是从哪里把这个自己构造的converter 注册进去。从BeanUtilsBeanUtilsBean再到ConvertUtilsBean的找,发现都是写死的调用ConvertUtilsBean.deregister()方法注册的,最后发现ConvertUtilsBean有个register(Converter converter, Class clazz)方法可以注册,而ConvertUtilsBean又是在BeanUtilsBeannew出来的,那么只要获取到这个ConvertUtilsBean即可,BeanUtilsBean提供了获取的方法。因此在BeanUtils.copyProperties(b, a);加上下面这句代码即可

BeanUtilsBean.getInstance().getConvertUtils().register(new SqlDateConverter(null),Date.class);

另外有一个辅助类也可以,

ConvertUtils.register(new SqlDateConverter(null),Date.class);

 

<!--[if !supportLists]-->l  <!--[endif]-->方法二

    从上面copyProperty方法可以看出,只有找到注册过的转化器,才使用转化器进行对值的转化,否则直接copy value。而deregister中并没有对java.util.Date注册相应的转化器,所以把java.sql.Date改为java.util.Date也可以解决问题。

 

<!--[if !supportLists]-->l  <!--[endif]-->方法三

       java.sql.Date的转化器去掉ConvertUtils.deregister(Date.class);

 

问题延伸

       从上述分析可以看出,拷贝含有java.sql.Timejava.sql.Timestampjava.io.Filejava.net.URL等类型的null属性也会有类似的问题,使用时需要多加小心。

       在字段属性比较明确并且较少的情况下,单单为了简化代码或者使代码优雅而引入BeanUtils这种相对复杂的copy机制是否值得,需要权衡,毕竟它增加了复杂性也牺牲了一些性能的。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值