Javers对比实体与DTO问题求助:仅获新增/移除对象无法取值变更
解决Javers跨Entity/DTO对比只返回NewObject/ObjectRemoved的问题
嘿,我之前也碰到过类似的Javers跨类型对比的坑,咱们先搞清楚问题根源,再一步步解决它!
问题原因
Javers默认是通过类的全限定名 + 对象ID来识别“同一个对象”的。你的Entity和EntityDTO是完全不同的Java类,所以Javers会把它们当成两个毫无关系的对象——一边是要移除的旧对象,另一边是新增的新对象,自然就只返回ObjectRemoved和NewObject这两种变更了,而不会识别为属性变更。
解决方案
要让Javers把这两个不同类的对象当成同一个对象来对比,核心是让Javers识别它们的“身份一致性”,同时统一类型标识,下面给你两种可行的实现方式:
方式一:用@TypeName统一类型别名 + 手动指定全局ID
首先给两个类加上@TypeName注解,让Javers把它们归为同一种类型:
import org.javers.core.metamodel.annotation.TypeName; @TypeName("Entity") // 统一类型别名 public class Entity { private ObjectId id; private String name; private String description; // getter/setter 省略 } @TypeName("Entity") // 和Entity用同一个别名 public class EntityDTO { private String name; // getter/setter 省略 }
然后在对比的时候,手动给两个对象指定同一个GlobalId,告诉Javers它们是同一个实例:
// 初始化测试对象 Entity oldState = new Entity(new ObjectId("1"), "OldProductName", "OldDesc"); EntityDTO newState = new EntityDTO("NewProductName"); // 构建Javers实例 Javers javers = JaversBuilder.javers().build(); // 手动创建全局ID,关联两个对象的身份 GlobalId targetId = GlobalId.createFromInstanceId("Entity", oldState.getId()); // 执行对比,传入统一的GlobalId Diff diff = javers.compare(oldState, newState, targetId, targetId); // 现在就能拿到name属性的变更了 for (Change change : diff.getChanges()) { System.out.println(change); }
方式二:自定义IdProvider(适合DTO无ID字段的场景)
如果你的DTO里没有id字段,可以通过自定义IdProvider来告诉Javers如何识别对象身份,同时配合TypeName统一类型:
// 自定义IdProvider,假设你通过业务规则确定DTO对应的Entity ID class EntityDTOIdProvider implements IdProvider { @Override public Object getId(Object domainObject) { if (domainObject instanceof EntityDTO) { // 这里根据你的业务逻辑返回对应的Entity ID,比如从上下文或DTO的其他字段获取 return "固定ID或业务推导的ID"; } return IdProvider.DEFAULT.getId(domainObject); } } // 构建Javers时注册这个IdProvider和TypeName Javers javers = JaversBuilder.javers() .withTypeNameMapping(new TypeNameMapping(Entity.class, "Entity")) .withTypeNameMapping(new TypeNameMapping(EntityDTO.class, "Entity")) .withIdProvider(new EntityDTOIdProvider()) .build(); // 直接对比即可,Javers会自动识别身份 Diff diff = javers.compare(oldState, newState);
额外提示
- Javers只会对比两个对象共同拥有的属性,比如
description只在Entity里有,DTO里没有,对比时会自动忽略这个属性,不会标记为移除。 - 如果只想关注特定属性,可以用
DiffBuilder来过滤:
Diff diff = DiffBuilder.compare(oldState, newState) .withJavers(javers) .includeProperty("name") .build();
内容的提问来源于stack exchange,提问作者efraimgentil
相关产品推荐
相关产品推荐

