我很难理解为什么以下内容不会给我相同的结果。
如果我使用Javers来比较两个列表(它们具有不同顺序的项目),那么我没有区别,因为我已经指定了AS_SET列表比较以忽略列表中项目的顺序。
如果我将这些列表作为对象的属性包装,则Javers返回List的元素不同,因为或列表中的项目顺序。
AS_SET是否应用于对象中的列表?就好像它被忽略了
public class App {
public static void main(String[] args) {
List<ListItem> list1 = ImmutableList.of(
ListItem.builder()
.itemName("item1")
.itemValue("value")
.build(),
ListItem.builder()
.itemName("item2")
.itemValue("value2")
.build()
);
List<ListItem> list2 = ImmutableList.of(
ListItem.builder()
.itemName("item2")
.itemValue("value2")
.build(),
ListItem.builder()
.itemName("item1")
.itemValue("value")
.build()
);
TopLevelClass tlc1 = TopLevelClass.builder().items(list1).build();
TopLevelClass tlc2 = TopLevelClass.builder().items(list2).build();
Diff diff = JaversBuilder.javers().withListCompareAlgorithm(ListCompareAlgorithm.AS_SET).build().compare(list1, list2);
System.out.println(diff);
Diff diffTlc = JaversBuilder.javers().withListCompareAlgorithm(ListCompareAlgorithm.AS_SET).build().compare(tlc1, tlc2);
System.out.println(diffTlc);
}
}
以下课程:
package wibble;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
@Builder
@Getter
@Setter
@EqualsAndHashCode
public class ListItem {
private String itemName;
private String itemValue;
}
package wibble;
import lombok.Builder;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.Setter;
import java.util.List;
@Builder
@Getter
@Setter
@EqualsAndHashCode
public class TopLevelClass {
List<ListItem> items;
}
上述运行时的输出:
Diff:
Diff:
* changes on wibble.TopLevelClass/ :
- 'items/0.itemName' changed from 'item1' to 'item2'
- 'items/0.itemValue' changed from 'value' to 'value2'
- 'items/1.itemName' changed from 'item2' to 'item1'
- 'items/1.itemValue' changed from 'value2' to 'value'
答案 0 :(得分:2)
有不同的方法(很多方法)
方法1 - 使用@Id
更新代码这类似于@kriegaex
建议的内容,是为代码添加@Id
注释并更新类,如下所示
public class ListItem {
@Id
private String itemName;
private String itemValue;
}
方法2 - 实体注册
Method 1
有一个缺点,它需要对您的实际模型进行代码更改,并且可能并不总是可行或不可取。在这种情况下,您需要手动注册您的实体
public static void main(String[] args) {
List<ListItem> list1 = ImmutableList.of(
ListItem.builder()
.itemName("item1")
.itemValue("value")
.build(),
ListItem.builder()
.itemName("item2")
.itemValue("value2")
.build()
);
List<ListItem> list2 = ImmutableList.of(
ListItem.builder()
.itemName("item2")
.itemValue("value2change")
.build(),
ListItem.builder()
.itemName("item1")
.itemValue("value")
.build(),
ListItem.builder()
.itemName("item3")
.itemValue("value3")
.build()
);
TopLevelClass tlc1 = TopLevelClass.builder().items(list1).build();
TopLevelClass tlc2 = TopLevelClass.builder().items(list2).build();
Javers jvc = JaversBuilder.javers().withListCompareAlgorithm(ListCompareAlgorithm.AS_SET)
.registerEntity(new EntityDefinition(ListItem.class, "itemName"))
.build();
Diff diffTlc = jvc.compare(tlc1, tlc2);
System.out.println(diffTlc);
}
以上运行的输出低于
* changes on com.javerstest.ListItem/item2 :
- 'itemValue' changed from 'value2' to 'value2change'
* changes on com.javerstest.TopLevelClass/ :
- 'items' collection changes :
. 'com.javerstest.ListItem@306a04bf' removed
. 'com.javerstest.ListItem@306a04fb' added
. 'com.javerstest.ListItem@29f62baf' added
* new object: com.javerstest.ListItem/item3
没有.registerEntity(new EntityDefinition(ListItem.class, "itemName"))
,它就是
* changes on com.javerstest.TopLevelClass/ :
- 'items' collection changes :
. 'com.javerstest.ListItem@306a04bf' removed
. 'com.javerstest.ListItem@306a04fb' added
. 'com.javerstest.ListItem@29f62baf' added
- 'items/0.itemName' changed from 'item1' to 'item2'
- 'items/0.itemValue' changed from 'value' to 'value2change'
- 'items/1.itemName' changed from 'item2' to 'item1'
- 'items/1.itemValue' changed from 'value2' to 'value'
方法3 - 使用@IgnoreDeclaredProperties
因此,在稍后的部分澄清之后,另一种方法是在
之下@IgnoreDeclaredProperties
public class ListItem {
private String itemName;
private String itemValue;
}
这将使List
比较工作和休息项目未添加。但这不会让您直接比较ListItem
。
因此,建议的方法是仅使用Method 2
,如果您不希望代码更改模型并且还具有完全的灵活性
方法4 - 使用@ShallowReference
可以在项目中添加@ShallowReference
,然后进行正确的设置比较
public class TopLevelClass {
@ShallowReference
List<ListItem> items;
}
目前截至 02-May-18 ,由于稍后解释的错误,此功能无法正常工作
方法5 - 使用集
如果您需要
,可以在班级中使用Set
代替List
public class TopLevelClass {
Set<ListItem> items;
}
更新的比较代码将是
TopLevelClass tlc1 = TopLevelClass.builder().items(new HashSet<ListItem>(list1)).build();
TopLevelClass tlc2 = TopLevelClass.builder().items(new HashSet<ListItem>(list2)).build();
Javers jvc = JaversBuilder.javers().build();
输出如下
Diff:
* new object: com.javerstest.TopLevelClass/#items/bd3fdf9ee4c8eb797ca392a1f8eb28c6
* new object: com.javerstest.TopLevelClass/#items/ad5b96d68b6742a92d330f0d98bae8b3
* object removed: com.javerstest.TopLevelClass/#items/a1961e7fd2e23b166e4d1b2acbe67263
* changes on com.javerstest.TopLevelClass/ :
- 'items' collection changes :
. 'com.javerstest.TopLevelClass/#items/a1961e7fd2e23b166e4d1b2acbe67263' removed
. 'com.javerstest.TopLevelClass/#items/bd3fdf9ee4c8eb797ca392a1f8eb28c6' added
. 'com.javerstest.TopLevelClass/#items/ad5b96d68b6742a92d330f0d98bae8b3' added
方法6 - 将ListItem注册为值
在此,您可以将ListItem
注册为值
Javers jvc = JaversBuilder.javers().withListCompareAlgorithm(ListCompareAlgorithm.AS_SET)
.registerValue(ListItem.class)
.build();
Diff diffTlc = jvc.compare(tlc1, tlc2);
System.out.println(diffTlc);
输出
* changes on com.javerstest.TopLevelClass/ :
- 'items' collection changes :
. 'com.javerstest.ListItem@306a04bf' removed
. 'com.javerstest.ListItem@306a04fb' added
. 'com.javerstest.ListItem@29f62baf' added
功能?/ BUG? /限制? 强>
如果您查看我们的Method2
没有.registerEntity(new EntityDefinition(ListItem.class, "itemName"))
* changes on com.javerstest.TopLevelClass/ :
- 'items' collection changes :
. 'com.javerstest.ListItem@306a04bf' removed
. 'com.javerstest.ListItem@306a04fb' added
. 'com.javerstest.ListItem@29f62baf' added
这基本上是因为ListCompareAlgorithm.AS_SET
,如果您将其更改为SIMPLE
,输出将更改为
- 'items' collection changes :
0. '...ListItem/item1' changed to '...ListItem/item2'
1. '...ListItem/item2' changed to '...ListItem/item1'
2. '...ListItem/item3' added
所以在我们的原始代码中
Javers jvc = JaversBuilder.javers().withListCompareAlgorithm(ListCompareAlgorithm.AS_SET).build();
Diff diffTlc = jvc.compare(tlc1, tlc2);
首先,它只使用list
set
进行比较,并添加如下所示的更改
* changes on com.javerstest.TopLevelClass/ :
- 'items' collection changes :
. 'com.javerstest.ListItem@306a04bf' removed
. 'com.javerstest.ListItem@306a04fb' added
. 'com.javerstest.ListItem@29f62baf' added
但是它再次走得更远,并在阵列的每个项目上做另一个差异,这就是为什么要添加额外的差异
- 'items/0.itemName' changed from 'item1' to 'item2'
- 'items/0.itemValue' changed from 'value' to 'value2change'
- 'items/1.itemName' changed from 'item2' to 'item1'
- 'items/1.itemValue' changed from 'value2' to 'value'
所以不是AS_SET
没有被挑选,而是差异首先是list
set
和个别项目级别。我提出了同样的问题,以便更好地理解
答案 1 :(得分:1)
正如@kriegaex已经提到的,您可以将ListItem
映射为实体或值,它可以解决问题。但这将是解决方法,因为ListItem
看起来像值对象。另一种解决方法是将List更改为Set。
看起来,现在你无法比较列表中的值对象和AS_SET算法。在这种情况下,生成ValueObjectIds存在问题。这里继续讨论https://github.com/javers/javers/issues/669
答案 2 :(得分:0)
免责声明:其实我以前从未听说过JaVers,我只是偶然发现了这个问题而变得很好奇。所以我在这里是一个完整的新手。
查看JaVers手册中的diff examples,您可以阅读以下内容:
<强>配置强>
JaVers需要知道
$ wget https://storage.googleapis.com/download.tensorflow.org/models/inceptions5h.zip
类是Employee
(...)这足以使用Entity
注释(...)注释名称字段
所以让我们试试这个:
@Id
控制台日志变为:
package wibble;
import lombok.*;
import org.javers.core.metamodel.annotation.Id;
@Builder
@Getter
@Setter
@EqualsAndHashCode
@ToString
public class ListItem {
@Id
private String itemName;
private String itemValue;
}
我希望这就是你想要的。