diff --git a/QLACK-Fuse/qlack-fuse-acv/README.md b/QLACK-Fuse/qlack-fuse-acv/README.md
index abefb338..5cf2081e 100644
--- a/QLACK-Fuse/qlack-fuse-acv/README.md
+++ b/QLACK-Fuse/qlack-fuse-acv/README.md
@@ -3,17 +3,20 @@
This module provides Object Auditing, Comparison and Versioning operations.
## Integration
-Add following property in your projects application.properties file, in order to persist the
+Add following property in your projects application.properties file, in order to persist the
object versions in the database used by your application.
-`javers.sqlSchema.sqlSchemaManagementEnabled=true`
+`javers.sqlSchemaManagementEnabled=true`
+
+This is Javers' default, so the property only needs to be set explicitly when it has been
+disabled elsewhere.
### Add qlack-fuse-acv dependency to your pom.xml:
```xml
- com.eurodyn.qlack.fuse
- qlack-fuse-acv
- ${qlack.version}
-
+ com.eurodyn.qlack.fuse
+ qlack-fuse-acv
+ ${qlack.version}
+
```
### Add the packages in the Spring boot application main class declaration:
diff --git a/QLACK-Fuse/qlack-fuse-acv/pom.xml b/QLACK-Fuse/qlack-fuse-acv/pom.xml
index 711878bd..e7b6e704 100644
--- a/QLACK-Fuse/qlack-fuse-acv/pom.xml
+++ b/QLACK-Fuse/qlack-fuse-acv/pom.xml
@@ -13,7 +13,7 @@
- 5.15.0
+ 7.11.7
diff --git a/QLACK-Fuse/qlack-fuse-acv/src/main/java/com/eurodyn/qlack/fuse/acv/service/CompareService.java b/QLACK-Fuse/qlack-fuse-acv/src/main/java/com/eurodyn/qlack/fuse/acv/service/CompareService.java
index ddf01c41..e9db86d4 100644
--- a/QLACK-Fuse/qlack-fuse-acv/src/main/java/com/eurodyn/qlack/fuse/acv/service/CompareService.java
+++ b/QLACK-Fuse/qlack-fuse-acv/src/main/java/com/eurodyn/qlack/fuse/acv/service/CompareService.java
@@ -7,6 +7,8 @@
import lombok.NonNull;
import org.javers.core.Javers;
import org.javers.core.diff.Diff;
+import org.javers.core.diff.changetype.InitialValueChange;
+import org.javers.core.diff.changetype.TerminalValueChange;
import org.javers.core.diff.changetype.ValueChange;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -56,12 +58,32 @@ public List compare(@NonNull T obj1, @NonNull T obj2) {
Diff result = javers.compare(obj1, obj2);
List changes = result.getChangesByType(ValueChange.class)
- .parallelStream()
- .map(this::convertToChangeDTO).collect(Collectors.toList());
+ .parallelStream()
+ .filter(CompareService::isValueChange)
+ .map(this::convertToChangeDTO).collect(Collectors.toList());
return Collections.unmodifiableList(changes);
}
+ /**
+ * Keeps only real, before/after property value changes.
+ *
+ * Javers 7 reports the whole state of an added or a removed object as
+ * {@link InitialValueChange} and {@link TerminalValueChange}. Both extend
+ * {@link ValueChange}, so they are also returned by
+ * {@link Diff#getChangesByType(Class)}, which would add one entry per
+ * property of every added/removed object, each having either the "from" or
+ * the "to" side always null. Such entries were not produced by earlier Javers
+ * versions and are filtered out here.
+ *
+ * @param change the change to examine
+ * @return true if the change is a plain value change, else false
+ */
+ private static boolean isValueChange(ValueChange change) {
+ return !(change instanceof InitialValueChange)
+ && !(change instanceof TerminalValueChange);
+ }
+
/**
* Compares two object versions and returns the changes.
*
@@ -74,10 +96,10 @@ public List compare(@NonNull T obj1, @NonNull T obj2) {
* @return a list with the changes between the two comparing objects
*/
public List compareVersions(Object object, long version1,
- long version2) {
+ long version2) {
return compare(versioningService.retrieveVersion(object, version1),
- versioningService.retrieveVersion(object, version2));
+ versioningService.retrieveVersion(object, version2));
}
/**
diff --git a/QLACK-Fuse/qlack-fuse-acv/src/test/java/com/eurodyn/qlack/fuse/acv/service/CompareServiceTest.java b/QLACK-Fuse/qlack-fuse-acv/src/test/java/com/eurodyn/qlack/fuse/acv/service/CompareServiceTest.java
index 25d3cb16..12dc59fd 100644
--- a/QLACK-Fuse/qlack-fuse-acv/src/test/java/com/eurodyn/qlack/fuse/acv/service/CompareServiceTest.java
+++ b/QLACK-Fuse/qlack-fuse-acv/src/test/java/com/eurodyn/qlack/fuse/acv/service/CompareServiceTest.java
@@ -4,13 +4,17 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.when;
+import com.eurodyn.qlack.fuse.acv.dto.ChangeDTO;
+import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.javers.core.Javers;
import org.javers.core.diff.Diff;
+import org.javers.core.diff.changetype.InitialValueChange;
import org.javers.core.diff.changetype.PropertyChangeMetadata;
import org.javers.core.diff.changetype.PropertyChangeType;
+import org.javers.core.diff.changetype.TerminalValueChange;
import org.javers.core.diff.changetype.ValueChange;
import org.javers.core.metamodel.object.GlobalId;
import org.junit.jupiter.api.BeforeEach;
@@ -69,7 +73,7 @@ public void compareVersionsTest() {
when(diff.getChangesByType(ValueChange.class)).thenReturn(valueChangeList);
assertEquals(Collections.emptyList(),
- compareService.compareVersions(object1, 1L, 2L));
+ compareService.compareVersions(object1, 1L, 2L));
}
@Test
@@ -82,7 +86,7 @@ public void testHasChanges() {
@Test
public void hasChangesNullObj1Test() {
assertThrows(NullPointerException.class, () ->
- compareService.hasChanges(null, object2));
+ compareService.hasChanges(null, object2));
}
@Test
@@ -113,7 +117,7 @@ public void compareObjectWithVersionTest() {
when(diff.getChangesByType(ValueChange.class)).thenReturn(valueChangeList);
assertEquals(Collections.emptyList(),
- compareService.compareObjectWithVersion(object1, 1L));
+ compareService.compareObjectWithVersion(object1, 1L));
}
@Test
@@ -123,16 +127,48 @@ public void compareObjectWithLatestVersionTest() {
when(diff.getChangesByType(ValueChange.class)).thenReturn(valueChangeList);
assertEquals(Collections.emptyList(),
- compareService.compareObjectWithLatestVersion(object1));
+ compareService.compareObjectWithLatestVersion(object1));
}
@Test
public void convertToChangeDTOTest() {
PropertyChangeMetadata metadata = new PropertyChangeMetadata(globalId, "property", Optional.empty(),
- PropertyChangeType.PROPERTY_VALUE_CHANGED);
+ PropertyChangeType.PROPERTY_VALUE_CHANGED);
ValueChange valueChange = new ValueChange(metadata, object1, object2);
assertNotNull(compareService.convertToChangeDTO(valueChange));
}
+ /**
+ * Since Javers 7, {@link Diff#getChangesByType(Class)} also returns the
+ * {@link InitialValueChange} and {@link TerminalValueChange} subtypes, which
+ * describe the state of added/removed objects rather than an actual
+ * before/after change. Those must not end up in the reported changes.
+ */
+ @Test
+ public void compareSkipsInitialAndTerminalValueChangesTest() {
+ ValueChange valueChange = new ValueChange(
+ propertyChangeMetadata("property"), object1, object2);
+ InitialValueChange initialValueChange = new InitialValueChange(
+ propertyChangeMetadata("addedProperty"), object2);
+ TerminalValueChange terminalValueChange = new TerminalValueChange(
+ propertyChangeMetadata("removedProperty"), object1);
+
+ when(javers.compare(object1, object2)).thenReturn(diff);
+ when(diff.getChangesByType(ValueChange.class)).thenReturn(
+ Arrays.asList(initialValueChange, valueChange, terminalValueChange));
+
+ List changes = compareService.compare(object1, object2);
+
+ assertEquals(1, changes.size());
+ assertEquals("property", changes.get(0).getPropertyName());
+ assertEquals(object1, changes.get(0).getFrom());
+ assertEquals(object2, changes.get(0).getTo());
+ }
+
+ private PropertyChangeMetadata propertyChangeMetadata(String propertyName) {
+ return new PropertyChangeMetadata(globalId, propertyName, Optional.empty(),
+ PropertyChangeType.PROPERTY_VALUE_CHANGED);
+ }
+
}
diff --git a/pom.xml b/pom.xml
index d152ed55..11c60de3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,10 +60,10 @@
5.15.2
- 8.7.0
+ 8.8.0
1.6.0
5.4.0
- 3.2.2
+ 3.3.2
2.0b6
1.80
2.18.0