Javers findChanges未捕获嵌套值对象更新问题求助
问题描述
持久化不含exclusions的Foo实体后,更新实体添加exclusion值时出现异常:Javers的findChanges方法未捕获到更新操作,但快照和影子查询能看到版本变化,日志显示无变更,可原始实体与更新后实体的哈希值确实不同。
相关代码
实体类 Foo
@NoArgsConstructor @AllArgsConstructor @ToString(onlyExplicitlyIncluded = true) @Builder(toBuilder = true) @Getter @Setter @Entity public class Foo { @ToString.Include @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ToString.Include @Valid @NotNull @AttributeOverride( name = "origin.elementType", column = @Column(name = "inclusion_origin_element_type", nullable = false) ) @AttributeOverride(name = "origin.values", column = @Column(name = "inclusion_origin_value", length = 64)) @AttributeOverride(name = "destination.elementType", column = @Column(name = "inclusion_destination_element_type")) @AttributeOverride(name = "destination.values", column = @Column(name = "inclusion_destination_value", length = 64)) @AttributeOverride(name = "bothDirections", column = @Column(name = "inclusion_both_direction", nullable = false)) @Embedded private CompositionDetails inclusions; @ToString.Include @Valid @Nullable @AttributeOverride(name = "origin.elementType", column = @Column(name = "exclusion_origin_element_type")) @AttributeOverride(name = "origin.values", column = @Column(name = "exclusion_origin_value", length = 64)) @AttributeOverride(name = "destination.elementType", column = @Column(name = "exclusion_destination_element_type")) @AttributeOverride(name = "destination.values", column = @Column(name = "exclusion_destination_value", length = 64)) @AttributeOverride(name = "bothDirections", column = @Column(name = "exclusion_both_direction")) @Embedded private CompositionDetails exclusions; //...... }
可嵌入类 CompositionDetails
@ToString @NoArgsConstructor @AllArgsConstructor @Builder @Getter @Setter @Embeddable public class CompositionDetails { @Valid @NotNull @Embedded private CompositionElement origin; @Valid @Nullable @Embedded private CompositionElement destination; @Builder.Default @Nullable private Boolean bothDirections = Boolean.FALSE; }
可嵌入类 CompositionElement
@ToString @NoArgsConstructor @AllArgsConstructor @Builder @Getter @Setter @Embeddable public class CompositionElement { @NotNull @Column(nullable = false, length = 16) @Enumerated(EnumType.STRING) private ElementType elementType; @Builder.Default @NotEmpty @ElementCollection(fetch = FetchType.EAGER) private List<String> values = new ArrayList<>(); }
异常现象
- 调用
javers.findChanges(QueryBuilder.byInstanceId(id, clazz).withChildValueObjects(true).build())仅返回初始的“创建”变更,未捕获到更新操作 - 调用
javers.findSnapshots(QueryBuilder.byInstanceId(id, clazz).withChildValueObjects(true).build())能看到两个版本,且exclusion已更新 - 调用
javers.findShadows(QueryBuilder.byInstanceId(id, clazz).withChildValueObjects(true).build())显示两个版本,分别为无exclusion的基础版本和含exclusion的新版本
更新日志
org.javers.core.Javers : Commit(id:11.00, snapshots:3, author:unknown, changes -), done in 5 ms (diff:4 ms, persist:1 ms)
环境信息
- JDK:21 (OpenJDK / Eclipse Temurin)
- spring-boot-starter-parent:3.3.4
- javers-spring-boot-starter-sql:7.6.2
问题原因及解决办法
- 关闭null属性忽略配置
Javers默认可能开启了ignore-null-properties,导致属性从null变为非null的变更被忽略。在配置文件中显式关闭该选项:
javers: diff: ignore-null-properties: false
- 给值对象添加属性比较注解
虽然Javers会自动遍历属性比较,但为了避免逻辑歧义,给CompositionDetails和CompositionElement添加@EqualsAndHashCode注解,确保属性级比较逻辑正确:
// 给CompositionDetails添加@EqualsAndHashCode @EqualsAndHashCode @ToString @NoArgsConstructor @AllArgsConstructor @Builder @Getter @Setter @Embeddable public class CompositionDetails { // 原有代码 } // 给CompositionElement添加@EqualsAndHashCode @EqualsAndHashCode @ToString @NoArgsConstructor @AllArgsConstructor @Builder @Getter @Setter @Embeddable public class CompositionElement { // 原有代码 }
- 验证Javers提交触发逻辑
如果用Spring Boot Starter,确保Repository接口添加@JaversSpringDataAuditable注解,或者继承JaversSpringDataAuditableRepository,保证实体更新时Javers自动触发提交:
@JaversSpringDataAuditable public interface FooRepository extends JpaRepository<Foo, Integer> { }
- 排查版本兼容性
当前Javers 7.6.2与Spring Boot 3.3.4可能存在兼容性bug,尝试升级Javers到最新稳定版本(如7.10.0)验证问题是否修复。
内容的提问来源于stack exchange,提问作者asceta
相关产品推荐
相关产品推荐

