From 0877e946a996abad24248c6a87aa4727ec038181 Mon Sep 17 00:00:00 2001
From: Benjamin Eckstein <13351939+benjamineckstein@users.noreply.github.com>
Date: Tue, 19 Nov 2019 16:04:22 +0100
Subject: [PATCH] TSK-950: Test pojo implementation of equals and hashcode
---
lib/taskana-core/pom.xml | 6 ++
.../src/main/java/pro/taskana/KeyDomain.java | 2 +-
.../java/pro/taskana/ObjectReference.java | 2 +-
.../main/java/pro/taskana/TimeInterval.java | 2 +-
.../java/pro/taskana/impl/AttachmentImpl.java | 2 +-
.../taskana/impl/AttachmentSummaryImpl.java | 2 +-
.../pro/taskana/impl/ClassificationImpl.java | 16 ++++-
.../impl/ClassificationSummaryImpl.java | 16 ++++-
.../main/java/pro/taskana/impl/TaskImpl.java | 2 +-
.../pro/taskana/impl/TaskSummaryImpl.java | 2 +-
.../impl/WorkbasketAccessItemImpl.java | 18 +++++-
.../java/pro/taskana/impl/WorkbasketImpl.java | 4 +-
.../taskana/impl/WorkbasketSummaryImpl.java | 2 +-
.../pro/taskana/EqualsAndHashCodeTest.java | 59 +++++++++++++++++++
pom.xml | 1 +
15 files changed, 124 insertions(+), 12 deletions(-)
create mode 100644 lib/taskana-core/src/test/java/pro/taskana/EqualsAndHashCodeTest.java
diff --git a/lib/taskana-core/pom.xml b/lib/taskana-core/pom.xml
index bb78db67b..6f937a947 100644
--- a/lib/taskana-core/pom.xml
+++ b/lib/taskana-core/pom.xml
@@ -102,6 +102,12 @@
${version.log4j}
test
+
+ nl.jqno.equalsverifier
+ equalsverifier
+ ${version.equalsverifier}
+ test
+
diff --git a/lib/taskana-core/src/main/java/pro/taskana/KeyDomain.java b/lib/taskana-core/src/main/java/pro/taskana/KeyDomain.java
index bf6f07763..370a7b818 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/KeyDomain.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/KeyDomain.java
@@ -56,7 +56,7 @@ public class KeyDomain {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
KeyDomain other = (KeyDomain) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/ObjectReference.java b/lib/taskana-core/src/main/java/pro/taskana/ObjectReference.java
index acdae406f..4e9b6298b 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/ObjectReference.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/ObjectReference.java
@@ -90,7 +90,7 @@ public class ObjectReference {
if (other == null) {
return false;
}
- if (other.getClass() != getClass()) {
+ if (!getClass().isAssignableFrom(other.getClass())) {
return false;
}
ObjectReference o = (ObjectReference) other;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/TimeInterval.java b/lib/taskana-core/src/main/java/pro/taskana/TimeInterval.java
index 67c1d9e14..d2aa40945 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/TimeInterval.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/TimeInterval.java
@@ -73,7 +73,7 @@ public class TimeInterval {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
TimeInterval other = (TimeInterval) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java
index 32ff9e775..58ab95021 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentImpl.java
@@ -166,7 +166,7 @@ public class AttachmentImpl implements Attachment {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
AttachmentImpl other = (AttachmentImpl) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentSummaryImpl.java
index 8491094ce..543b6d25c 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentSummaryImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/AttachmentSummaryImpl.java
@@ -161,7 +161,7 @@ public class AttachmentSummaryImpl implements AttachmentSummary {
if (obj == null) {
return false;
}
- if (!(obj instanceof AttachmentSummaryImpl)) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
AttachmentSummaryImpl other = (AttachmentSummaryImpl) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java
index ddff3fc44..cf1557bbd 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationImpl.java
@@ -134,13 +134,23 @@ public class ClassificationImpl extends ClassificationSummaryImpl implements Cla
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (o == null) {
return false;
}
+
+ if (!getClass().isAssignableFrom(o.getClass())) {
+ return false;
+ }
+
if (!super.equals(o)) {
return false;
}
ClassificationImpl that = (ClassificationImpl) o;
+
+ if (!that.canEqual(this)) {
+ return false;
+ }
+
return Objects.equals(isValidInDomain, that.isValidInDomain)
&& Objects.equals(created, that.created)
&& Objects.equals(modified, that.modified)
@@ -148,6 +158,10 @@ public class ClassificationImpl extends ClassificationSummaryImpl implements Cla
&& Objects.equals(applicationEntryPoint, that.applicationEntryPoint);
}
+ protected boolean canEqual(Object other) {
+ return (other instanceof ClassificationImpl);
+ }
+
@Override
public int hashCode() {
return Objects.hash(super.hashCode(), isValidInDomain, created, modified, description, applicationEntryPoint);
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationSummaryImpl.java
index 4b7fc829f..09cfab9e8 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationSummaryImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/ClassificationSummaryImpl.java
@@ -198,10 +198,20 @@ public class ClassificationSummaryImpl implements ClassificationSummary {
if (this == o) {
return true;
}
- if (o == null || getClass() != o.getClass()) {
+ if (o == null) {
return false;
}
+
+ if (!getClass().isAssignableFrom(o.getClass())) {
+ return false;
+ }
+
ClassificationSummaryImpl that = (ClassificationSummaryImpl) o;
+
+ if (!that.canEqual(this)) {
+ return false;
+ }
+
return priority == that.priority
&& Objects.equals(id, that.id)
&& Objects.equals(key, that.key)
@@ -222,6 +232,10 @@ public class ClassificationSummaryImpl implements ClassificationSummary {
&& Objects.equals(custom8, that.custom8);
}
+ protected boolean canEqual(Object other) {
+ return (other instanceof ClassificationSummaryImpl);
+ }
+
@Override
public int hashCode() {
return Objects.hash(id, key, category, type, domain, name, parentId, parentKey, priority, serviceLevel, custom1,
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java
index d31cc8379..dc7869cf5 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskImpl.java
@@ -774,7 +774,7 @@ public class TaskImpl implements Task {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
TaskImpl other = (TaskImpl) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java
index c15bad255..5bcbd7b47 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/TaskSummaryImpl.java
@@ -552,7 +552,7 @@ public class TaskSummaryImpl implements TaskSummary {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
TaskSummaryImpl other = (TaskSummaryImpl) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketAccessItemImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketAccessItemImpl.java
index 5f140fed0..5e5bf4edf 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketAccessItemImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketAccessItemImpl.java
@@ -461,6 +461,8 @@ public class WorkbasketAccessItemImpl implements WorkbasketAccessItem {
result = prime * result + (permRead ? 1231 : 1237);
result = prime * result + (permTransfer ? 1231 : 1237);
result = prime * result + ((workbasketId == null) ? 0 : workbasketId.hashCode());
+ result = prime * result + ((workbasketKey == null) ? 0 : workbasketKey.hashCode());
+ result = prime * result + ((accessName == null) ? 0 : accessName.hashCode());
return result;
}
@@ -472,7 +474,7 @@ public class WorkbasketAccessItemImpl implements WorkbasketAccessItem {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
WorkbasketAccessItemImpl other = (WorkbasketAccessItemImpl) obj;
@@ -548,6 +550,20 @@ public class WorkbasketAccessItemImpl implements WorkbasketAccessItem {
} else if (!workbasketId.equals(other.workbasketId)) {
return false;
}
+ if (workbasketKey == null) {
+ if (other.workbasketKey != null) {
+ return false;
+ }
+ } else if (!workbasketKey.equals(other.workbasketKey)) {
+ return false;
+ }
+ if (accessName == null) {
+ if (other.accessName != null) {
+ return false;
+ }
+ } else if (!accessName.equals(other.accessName)) {
+ return false;
+ }
return true;
}
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketImpl.java
index 92fa76338..200be9422 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketImpl.java
@@ -1,6 +1,7 @@
package pro.taskana.impl;
import java.time.Instant;
+
import pro.taskana.Workbasket;
import pro.taskana.WorkbasketSummary;
import pro.taskana.WorkbasketType;
@@ -262,7 +263,8 @@ public class WorkbasketImpl implements Workbasket {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
WorkbasketImpl other = (WorkbasketImpl) obj;
diff --git a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketSummaryImpl.java b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketSummaryImpl.java
index ef6515e8d..3d140a9b0 100644
--- a/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketSummaryImpl.java
+++ b/lib/taskana-core/src/main/java/pro/taskana/impl/WorkbasketSummaryImpl.java
@@ -263,7 +263,7 @@ public class WorkbasketSummaryImpl implements WorkbasketSummary {
if (obj == null) {
return false;
}
- if (getClass() != obj.getClass()) {
+ if (!getClass().isAssignableFrom(obj.getClass())) {
return false;
}
WorkbasketSummaryImpl other = (WorkbasketSummaryImpl) obj;
diff --git a/lib/taskana-core/src/test/java/pro/taskana/EqualsAndHashCodeTest.java b/lib/taskana-core/src/test/java/pro/taskana/EqualsAndHashCodeTest.java
new file mode 100644
index 000000000..bd237f350
--- /dev/null
+++ b/lib/taskana-core/src/test/java/pro/taskana/EqualsAndHashCodeTest.java
@@ -0,0 +1,59 @@
+package pro.taskana;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import org.junit.jupiter.api.DynamicTest;
+import org.junit.jupiter.api.TestFactory;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+import pro.taskana.impl.AttachmentImpl;
+import pro.taskana.impl.AttachmentSummaryImpl;
+import pro.taskana.impl.ClassificationImpl;
+import pro.taskana.impl.ClassificationSummaryImpl;
+import pro.taskana.impl.TaskImpl;
+import pro.taskana.impl.TaskSummaryImpl;
+import pro.taskana.impl.WorkbasketAccessItemImpl;
+import pro.taskana.impl.WorkbasketImpl;
+import pro.taskana.impl.WorkbasketSummaryImpl;
+
+/**
+ * check classes with a custom equals and hashcode implementation for correctness.
+ */
+class EqualsAndHashCodeTest {
+
+ @TestFactory
+ Collection equalsContract() {
+ return
+ getPojoClasses().stream()
+ .map(cl -> DynamicTest.dynamicTest("Check Hash and Equals for " + cl.getSimpleName(),
+ () -> {
+ EqualsVerifier.forClass(cl)
+ .suppress(Warning.NONFINAL_FIELDS, Warning.STRICT_INHERITANCE)
+ .withRedefinedSuperclass()
+ .verify();
+ }))
+ .collect(Collectors.toList());
+ }
+
+ //TODO find a way to dynamically create a list with custom implemented equals or hash methods.
+ private List> getPojoClasses() {
+ return Arrays.asList(
+ KeyDomain.class,
+ ObjectReference.class,
+ TimeInterval.class,
+ AttachmentImpl.class,
+ AttachmentSummaryImpl.class,
+ ClassificationImpl.class,
+ ClassificationSummaryImpl.class,
+ TaskImpl.class,
+ TaskSummaryImpl.class,
+ WorkbasketAccessItemImpl.class,
+ WorkbasketImpl.class,
+ WorkbasketSummaryImpl.class
+ );
+ }
+}
diff --git a/pom.xml b/pom.xml
index b581245fe..8f50e12f2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -69,6 +69,7 @@
2.8.47
1.7.1
1.3
+ 3.1.10
1.4.197