近期把一个老项目的spring版本从3.1.1.RELEASE升级到了3.2.18.RELEASE, 结果线上出现了一堆问题, 经排查是一个bean实例某几个int类型属性值为0致使的, 这个bean的值是查询接口, 而后经过spring的工具类方法org.springframework.beans.BeanUtils.copyProperties(Object, Object)
赋值, 而source bean的这几个属性类型为long(target bean这几个属性类型为int), 把spring版本回退到3.1.1.RELEASE问题消失.spring
经排查, spring的BeanUtils从3.2.7.RELEASE开始, copyProperties方法加了类型校验, source的属性获取方法返回类型和target的属性写入方法的参数类型不一致就跳过赋值, 3.2.7.RELEASE中copyProperties方法属性copy代码以下:工具
for (PropertyDescriptor targetPd : targetPds) { 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); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } catch (Throwable ex) { throw new FatalBeanException( "Could not copy property '" + targetPd.getName() + "' from source to target", ex); } } } } }
3.2.6中copyProperties方法属性copy代码以下:测试
for (PropertyDescriptor targetPd : targetPds) { if (targetPd.getWriteMethod() != null && (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null && sourcePd.getReadMethod() != null) { try { Method readMethod = sourcePd.getReadMethod(); if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); Method writeMethod = targetPd.getWriteMethod(); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } catch (Throwable ex) { throw new FatalBeanException("Could not copy properties from source to target", ex); } } } }
3.2.7.RELEASE中添加了判断if (readMethod != null && ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType()))
代码规范
咱们解决方法是, 修改了这几个属性的参数赋值方式.
最终说一下经验教训吧:code