问题背景
由于想使用 cn.hutool.core.net.URLEncodeUtil
方法,而原来的 Hutool 5.7.9 版本不包含这一功能,所以升级到了 5.8.29。
后续发现线上数据异常,经排查 BeanUtil.copyProperties
失效,代码如下
BeanUtil.copyProperties(
trafficUnit,
record,
CopyOptions.create().setPropertiesFilter(
(t, u) -> REVERSED_FIELD_MAPPING.containsKey(t.getName()) && Convert.toLong(u, -1L) > 0
).setFieldMapping(FIELD_MAPPING));
这个代码 trafficUnit 对象和 record 对象不是同一个类,字段命名不一致但含义一致,将数据进行拷贝
先说结论
- 5.7.9 版本 PropertiesFilter 传入的字段是
(targetField, sourceValue)
- 5.8.29 版本 PropertiesFilter 传入的字段是
(sourceField, sourceValue)
- 如果源和目标字段名不一致,并且使用了自定义的
PropertiesFilter
来校验字段名满足一定条件才进行拷贝,就会导致 bug
所以更新版本后,上面的代码片段中,所有的字段都无法通过 REVERSED_FIELD_MAPPING.containsKey(t.getName())
的检测,因为传入的 t
完全就不是一个东西了。
5.7.9 版本源码
假设:source => dest
- 代码位置:
cn.hutool.core.bean.copier.BeanCopier#valueProviderToBean
- 代码基本逻辑:遍历 dest 实际可编辑的所有 field,尝试在满足条件的情况下进行数据拷贝
PropertiesFilter
生效位置和代码:256 行,这里的prop
是 dest 的 fieldif(null != copyOptions.propertiesFilter && false == copyOptions.propertiesFilter.test(prop.getField(), value)) { return; }
5.8.29 版本源码
假设:source => dest
- 代码位置:
cn.hutool.core.bean.copier.BeanToBeanCopier#copy
- 代码基本逻辑:遍历 source 的所有 field,尝试在满足条件的情况下进行数据拷贝
PropertiesFilter
生效位置和代码:77 行,这里已经明确看出来传入的是 source 的 fieldif(false == copyOptions.testPropertyFilter(sDesc.getField(), sValue)) { return; }