BeanUtils代码改写成BeanCopier时出现的问题

错误案例

短信平台大量的使用到了org.apache.commons.beanutils.BeanUtils的copyProperties(Object dest, Object orig)方法。而这个方法存在性能问题,在性能优化小组的建议下改使用net.sf.cglib.beans.BeanCopier的copy(Object from, Object to, Converter converter)方法将其替换。例如:

原来代码:
BeanUtils.copyProperties(cpInfoDO, cpInfo);                

改写后的代码:
BeanCopier beanCopier = BeanCopier.create(CPInfo.class, CPInfoDO.class, false);
beanCopier.copy(cpInfo, cpInfoDO, null);

自测时发现修改短信平台内容提供商的form提交总是失败,webx.log抛出的异常显示,插入数据库时,DO对象中非空字段出现了空值。

错误分析

比较了copy属性的两个对象,CPInfo中的status属性是StatusEnum类型(该类型继承了com.alibaba.common.lang.enumeration.IntegerEnum),而CPInfoDO中的status属性是String类型的。

1.使用BeanUtils进行属性拷贝时,CPInfo中的status属性值可以拷贝到CPInfo中的status属性值中,虽然两者类型不相同,而BeanCopier却不行。

结合本例分析BeanUtils的拷贝属性是通过反射实现的,关键代码实现和分析如下:

BeanUtilsBean:
392  descriptor =getPropertyUtils().getPropertyDescriptor(target, name);   // 获得属性描述,这里target为CPInfoDO的一个实例,name为status
     ... 
400  type = descriptor.getPropertyType();                                  // 获得属性的类型,CPInfoDO的类型是String
     ...
441  Converter converter = getConvertUtils().lookup(type);                 // 查找String类型的转换器,StringConverter 
442  if (converter != null) {
443     log.trace("        USING CONVERTER " + converter);
444     value = converter.convert(type, value);                            // 进行转换,value是CPInfo实例的status属性
445  }

StringConverter:    
   public Object convert(Class type, Object value) {
      if (value == null) {
         return ((String) null);
      } else {
         return (value.toString());                                        // 虽然StatusEnum不是String类型,但是它有toString方法,所以不同类型的属性还是可以copy成功
      }
   }

2.BeanCopier会通过字节码生成动态代理对象,代理对象拷贝属性时会检查类型,类型不同认为是不同的属性,就不进行赋值拷贝了。


本例中CPInfo的status是StatusEnum类型的,CPInfoDO是String类型,两者类型不一致,不进行属性拷贝赋值。数据库插入时,CPInfoDO的status为null,于是就出现了非空字段插入为空的异常了。

正确用法

BeanCopier beanCopier = BeanCopier.create(CPInfo.class, CPInfoDO.class, false);
beanCopier.copy(cpInfo, cpInfoDO, null);
// beanCopier复制属性时,属性类型不同不能复制,需要自己set下
cpInfoDO.setStatus(cpInfo.getStatus().getName());

测试关注点

做好单元测试,保证方法输入输出一致

自动化回归测试,并关注后台日志


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值