Jen 发表于 2013-2-5 09:08:37

关于BeanUtils拷贝null属性的问题

关于BeanUtils拷贝null属性的问题
jen wang
 
       帮同事查看物流发货问题时,发现BeanUtils在copy null属性时会有一些问题。现在总结一下现象、原因和解决方法。
问题现象

       1.当源对象(a)中存在一个java.sql.Date类型的属性并且值为null,目标对象(b)中也存在这个同名同类型的属性。把a对象属性值copy给b时
        throwsIllegalAccessException, InvocationTargetException {
   
    ……
    if (getPropertyUtils().isReadable(orig, name) &&
         getPropertyUtils().isWriteable(dest,name)) {
           try {
                Object value =
                getPropertyUtils().getSimpleProperty(orig,name);
                <a name="OLE_LINK4">
           } catch (NoSuchMethodException e) {
                        ; // Should not happen
           }
    }
    ……
}
 
isWriteable这一行,当目标对象没有相应的属性时不进行copy,所以不会有问题(现象2)。
再看copyProperty方法的关键代码,

http://dl.iteye.com/upload/attachment/476405/06e8d924-cc83-39be-a3bc-2a26fe609d5f.jpg
 
引起现象1的代码为value =converter.convert(type, value);这行,这里会抛出一个类型转换错误。转化器在转化时报错,需要找出这个转化器,继续往下看代码,ConvertUtilsBean.lookup(Classclazz)方法,

http://dl.iteye.com/upload/attachment/476407/36ad8db9-3352-379a-a267-e687f4ab749d.jpg
 
再看converters中注册的转化器方法ConvertUtilsBean.deregister()的关键代码,

http://dl.iteye.com/upload/attachment/476409/788b45b7-8627-3985-bb2d-34b1ef64d182.jpg
  
找到了相应的转化器<a name="OLE_LINK7">SqlDateConverter,异常就在这个SqlDateConverter转化类型时抛出,当java.sql.Date类型的属性值为null时抛异常。

http://dl.iteye.com/upload/attachment/476411/9e105c88-510d-3f1e-829b-574374851596.jpg
 
解决方法

<!---->l  <!---->方法一
       从convert方法可以看出只要想办法把useDefault和defaultValue设值就能解决,SqlDateConverter的另外一个构造方法可以设置这两个值,问题是从哪里把这个自己构造的converter 注册进去。从BeanUtils到BeanUtilsBean再到ConvertUtilsBean的找,发现都是写死的调用ConvertUtilsBean.deregister()方法注册的,最后发现ConvertUtilsBean有个register(Converterconverter, Class clazz)方法可以注册,而ConvertUtilsBean又是在BeanUtilsBean里new出来的,那么只要获取到这个ConvertUtilsBean即可,BeanUtilsBean提供了获取的方法。因此在BeanUtils.copyProperties(b,a);加上下面这句代码即可
BeanUtilsBean.getInstance().getConvertUtils().register(newSqlDateConverter(null),Date.class);
另外有一个辅助类也可以,
ConvertUtils.register(newSqlDateConverter(null),Date.class);
 
<!---->l  <!---->方法二
    从上面copyProperty方法可以看出,只有找到注册过的转化器,才使用转化器进行对值的转化,否则直接copy value。而deregister中并没有对java.util.Date注册相应的转化器,所以把java.sql.Date改为java.util.Date也可以解决问题。
 
<!---->l  <!---->方法三
       把java.sql.Date的转化器去掉ConvertUtils.deregister(Date.class);
 
问题延伸

       从上述分析可以看出,拷贝含有java.sql.Time,java.sql.Timestamp,java.io.File,java.net.URL等类型的null属性也会有类似的问题,使用时需要多加小心。
       在字段属性比较明确并且较少的情况下,单单为了简化代码或者使代码优雅而引入BeanUtils这种相对复杂的copy机制是否值得,需要权衡,毕竟它增加了复杂性也牺牲了一些性能的。
 
 
页: [1]
查看完整版本: 关于BeanUtils拷贝null属性的问题