近期把一個老項目的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