DEBUG.WIKI
Evoxt;最高 6.0GHz CPU;高频云服务器 · 免费每周备份;查看配置 →
雨云;给项目一台云服务器
京东云;让 AI 进入真实业务;零售 · 物流 · 客服 · 硬件;查看方案 →

JaVers 7.11.5 比较嵌套 List 报 ClassCastException

JaVers7.11.5在AS_SET的快照哈希路径把List当Set转换。7.11.6正式版改用Collection接收这两类集合,修正时保留列表顺序、重复项与审计契约,不强改领域集合。

JaVers 7.11.5 采用 ListCompareAlgorithm.AS_SET 比较对象,遇到对象内部嵌套的 List 后抛出 ClassCastException。外层模型确实声明了 List,并没有把 Set 强行赋给它,仍要检查快照哈希使用的集合类型转换。

7.11.5 为含 Set 的值对象增加确定性哈希时,将 Set 和按集合语义比较的 List 放进同一处理分支。该分支把属性值转换成 Set<?>;AS_SET 改变的是比较语义,实际的 List 对象不会因此变成 Java Set,所以这次转换会失败。

嵌套List可以进入值对象哈希路径

下面是模型结构片段,构造器应按项目原来的方式初始化字段:

class Country {
    List<City> cities;
}

class City {
    List<String> streets;
}

当 cities 中的值对象还含有 streets,比较过程可能进入快照哈希和属性转换。先保留完整堆栈,确认异常位于 JaVers 的快照创建路径,而不是业务代码自己做了 List 到 Set 的强转。只用顶层字符串列表通过,也不能覆盖这一层嵌套结构。

采用7.11.6或含修正的兼容正式版本

正式 7.11.6 将这两类属性值共同按 Collection<?> 传给 toOrderedSet(),由接受 Collection 的辅助方法整理有序集合,不再把 List 直接强转为 Set。项目允许时升级到包含该修正的正式兼容版本,核对实际运行的 javers-core;使用 Spring 集成包时也要检查其解析到的核心版本。

暂时无法升级,可以评估恢复到升级前已经验证的版本组合。不要为了消除转换异常,把领域模型里的所有 List 改成 HashSet:这会改变顺序、重复元素和可能的持久化或 JSON 契约,并不只是更换 JaVers 内部实现。

把算法从 AS_SET 改成其他列表算法同样是语义变更。若业务本来不关心顺序与重复数,改成顺序敏感算法可能产生以前不会出现的审计差异;若顺序本来就重要,反而应独立重新确认 AS_SET 是否合适,不能只以“不抛异常”为选择标准。

验收既看异常,也看比较含义

保留原 JaversBuilder 配置,覆盖值对象中嵌套 List、空 List、成员变化、仅顺序变化和重复项。确认目标版本不会在相同属性上抛出转换错误,同时比较结果仍符合既定 AS_SET 语义。已有自定义值比较器或特殊元素类型时,还要覆盖原模型,不能从字符串元素的通过结果推出所有类型都兼容。

如果 JaVers 的快照已经写入仓库,保留原快照与事务边界;本题不需要清空审计数据库。恢复依赖只影响之后运行的比较,不会自动撤销故障期间业务已提交的修改,也不能凭异常就断言此前所有审计记录都错误。