Есть разные способы сделать это (их много)
Метод 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-мая-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
Функция? / Ошибка? / ограничение
Теперь еще одна вещь, которая происходит здесь, в коде ниже, если вы посмотрите на вывод нашего 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
Но затем он снова идет дальше и делает еще один diff для каждого элемента массива, поэтому добавляется дополнительный diff
- '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
, а также на уровне отдельного предмета. Я поднял вопрос о том же, чтобы лучше понять это
https://github.com/javers/javers/issues/669