diff --git a/db/pom.xml b/db/pom.xml
index abf9a62..85a7903 100644
--- a/db/pom.xml
+++ b/db/pom.xml
@@ -23,10 +23,33 @@
${project.groupId}
shared-util
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ test
+
+
+
org.slf4j
slf4j-api
+
+ org.slf4j
+ slf4j-log4j12
+ test
+
javax
javaee-web-api
diff --git a/db/src/main/java/de/muehlencord/shared/db/AbstractController.java b/db/src/main/java/de/muehlencord/shared/db/AbstractController.java
index 15a609e..b6baec5 100644
--- a/db/src/main/java/de/muehlencord/shared/db/AbstractController.java
+++ b/db/src/main/java/de/muehlencord/shared/db/AbstractController.java
@@ -41,7 +41,6 @@ import javax.persistence.metamodel.IdentifiableType;
import javax.persistence.metamodel.Metamodel;
import javax.persistence.metamodel.SingularAttribute;
import javax.transaction.Transactional;
-import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
/**
@@ -91,8 +90,9 @@ public abstract class AbstractController {
* @param cb the criteria builder to use
* @param root the root of the object to search for
* @param filters the filters to apply
- * @param include if set to true, the filter is used as include filter (equals, in). If set to false, the filter is
- * inverted and used as exclude filter (not equals, not in etc)
+ * @param include if set to true, the filter is used as include filter
+ * (equals, in). If set to false, the filter is inverted and used as exclude
+ * filter (not equals, not in etc)
* @return
*/
protected Predicate getFilterCondition(Predicate filterCondition, CriteriaBuilder cb, Root root, Map filters, boolean include) {
@@ -231,7 +231,7 @@ public abstract class AbstractController {
@Lock(LockType.WRITE)
public T update(T entity, String updatedBy) throws ControllerException {
T currentEntity = attach(entity);
- T newEntity = getClone(currentEntity);
+ T newEntity = EntityUtil.cloneToNewEntity(currentEntity);
if (Auditable.class.isAssignableFrom(entity.getClass())) {
Audit audit = ((Auditable) entity).getAudit();
((Auditable) entity).setAudit(applyAuditChanges(audit, false, updatedBy));
@@ -243,7 +243,7 @@ public abstract class AbstractController {
endDateable.setValidTo(DateUtil.getCurrentTimeInUTC());
em.merge(entity);
// and create new entity instead
-
+
return create(newEntity, updatedBy);
} else {
// if it is not enddatable, just update it (already done above)
@@ -325,8 +325,9 @@ public abstract class AbstractController {
}
/**
- * returns null, if the list is empty or null itself. Returns the one element if there is exactly one element in the
- * list. Otherwise an exception is thrown
+ * returns null, if the list is empty or null itself. Returns the one
+ * element if there is exactly one element in the list. Otherwise an
+ * exception is thrown
*
* @param resultList
* @return
@@ -348,19 +349,4 @@ public abstract class AbstractController {
// of.getDeclaredId(entityClass).getJavaMember().
return of.getId(of.getIdType().getJavaType());
}
-
- private T getClone(T entity) {
- T newEntity = SerializationUtils.clone(entity);
- // remove audit if class is auditable - it is a new clone
- if (Auditable.class.isAssignableFrom(newEntity.getClass())) {
- ((Auditable) newEntity).setAudit(null);
- }
- // set new valid dates if class is enddateable
- if (EndDateable.class.isAssignableFrom(newEntity.getClass())) {
- ((EndDateable) newEntity).setValidFrom(DateUtil.getCurrentTimeInUTC());
- ((EndDateable) newEntity).setValidTo(null);
- }
- return newEntity;
- }
-
}
diff --git a/db/src/main/java/de/muehlencord/shared/db/ControllerException.java b/db/src/main/java/de/muehlencord/shared/db/ControllerException.java
index a0d022f..978472a 100644
--- a/db/src/main/java/de/muehlencord/shared/db/ControllerException.java
+++ b/db/src/main/java/de/muehlencord/shared/db/ControllerException.java
@@ -1,62 +1,63 @@
-/*
- * Copyright 2019 joern.muehlencord.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package de.muehlencord.shared.db;
-
-import javax.ejb.ApplicationException;
-
-/**
- *
- * @author joern.muehlencord
- */
-@ApplicationException(rollback=true)
-public class ControllerException extends Exception {
-
- private static final long serialVersionUID = 5190280225284514859L;
- public static final int CAUSE_ALREADY_EXISTS = 1;
- public static final int CAUSE_NOT_FOUND = 2;
- public static final int CAUSE_CANNOT_PERSIST = 3;
- public static final int CAUSE_TOO_MANY_ROWS = 4;
- public static final int CAUSE_CANNOT_DELETE = 5;
-
- private final int causeCode;
-
- /**
- * Creates a new instance of ControllerException without detail
- * message.
- *
- * @param cause the reason code
- * @param message an explanation
- */
- public ControllerException(int cause, String message) {
- super(message);
- this.causeCode = cause;
- }
-
- /**
- *
- * @param causeCode
- * @param message
- * @param cause
- */
- public ControllerException(int causeCode, String message, Throwable cause) {
- super(message, cause);
- this.causeCode = causeCode;
- }
-
- public int getCauseCode() {
- return causeCode;
- }
-}
+/*
+ * Copyright 2019 joern.muehlencord.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.muehlencord.shared.db;
+
+import javax.ejb.ApplicationException;
+
+/**
+ *
+ * @author joern.muehlencord
+ */
+@ApplicationException(rollback = true)
+public class ControllerException extends Exception {
+
+ private static final long serialVersionUID = 5190280225284514859L;
+ public static final int INTERNAL_ERROR = 0;
+ public static final int CAUSE_ALREADY_EXISTS = 1;
+ public static final int CAUSE_NOT_FOUND = 2;
+ public static final int CAUSE_CANNOT_PERSIST = 3;
+ public static final int CAUSE_TOO_MANY_ROWS = 4;
+ public static final int CAUSE_CANNOT_DELETE = 5;
+
+ private final int causeCode;
+
+ /**
+ * Creates a new instance of ControllerException without detail
+ * message.
+ *
+ * @param cause the reason code
+ * @param message an explanation
+ */
+ public ControllerException(int cause, String message) {
+ super(message);
+ this.causeCode = cause;
+ }
+
+ /**
+ *
+ * @param causeCode
+ * @param message
+ * @param cause
+ */
+ public ControllerException(int causeCode, String message, Throwable cause) {
+ super(message, cause);
+ this.causeCode = causeCode;
+ }
+
+ public int getCauseCode() {
+ return causeCode;
+ }
+}
diff --git a/db/src/main/java/de/muehlencord/shared/db/EntityUtil.java b/db/src/main/java/de/muehlencord/shared/db/EntityUtil.java
new file mode 100644
index 0000000..4fa5267
--- /dev/null
+++ b/db/src/main/java/de/muehlencord/shared/db/EntityUtil.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2019 joern.muehlencord.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.muehlencord.shared.db;
+
+import de.muehlencord.shared.util.DateUtil;
+import java.beans.IntrospectionException;
+import java.beans.PropertyDescriptor;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import javax.persistence.Id;
+import org.apache.commons.lang3.SerializationUtils;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author joern.muehlencord
+ */
+public class EntityUtil {
+
+ private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(EntityUtil.class);
+
+ public static Field getIdField(Class> entity) {
+ if (entity == null) {
+ return null;
+ }
+
+ for (var f : entity.getDeclaredFields()) {
+ Id id = null;
+ Annotation[] as = f.getAnnotations();
+ for (Annotation a : as) {
+ if (a.annotationType() == Id.class) {
+ id = (Id) a;
+ }
+ }
+
+ if (id != null) {
+ return f;
+ }
+ }
+
+ // iterated over all fields, not found
+ return null;
+ }
+
+ public static T setIdValue(T entity, Object fieldValue) throws ControllerException {
+ Field field = getIdField(entity.getClass());
+
+ if (field == null) {
+ return entity;
+ }
+ if (LOGGER.isDebugEnabled()) {
+ LOGGER.debug("id column of {} is {}", entity.getClass().getSimpleName(), field.getName());
+ }
+
+ try {
+ PropertyDescriptor pd = new PropertyDescriptor(field.getName(), entity.getClass());
+ pd.getWriteMethod().invoke(entity, fieldValue);
+ return entity;
+ } catch (IllegalAccessException | InvocationTargetException | IntrospectionException ex) {
+ String hint = "Error setting value of field " + field.getName() + " to " + fieldValue;
+ if (fieldValue != null) {
+ hint += " of type " + fieldValue.getClass().getSimpleName();
+ }
+ throw new ControllerException(ControllerException.INTERNAL_ERROR, hint, ex);
+ }
+
+ }
+
+ /**
+ * clones the given entity and updates related fields so the entity appears as new.The following changes are executed
+ *
+ * - the Id field of the entity is set to null
+ * - if the entity is auditable, the audit is set to null.
+ * - if the entity is enddatable, validTo is set to null and validFrom is set to current sysdate (in UTC)
+ *
+ *
+ * @param the entity to be cloned - must implement serializeable to be cloned
+ * @param entity the entity to be cloned - must implement serializeable to be cloned
+ * @return the cloned entity with updated fields as described above
+ * @throws de.muehlencord.shared.db.ControllerException if the id value cannot be set to null
+ */
+ public static T cloneToNewEntity(T entity) throws ControllerException {
+ T newEntity = SerializationUtils.clone(entity);
+
+ // ensure id column is set to null
+ newEntity = setIdValue(newEntity, null);
+
+ // remove audit if class is auditable - it is a new clone
+ if (Auditable.class.isAssignableFrom(newEntity.getClass())) {
+ ((Auditable) newEntity).setAudit(null);
+ }
+
+ // set new valid dates if class is enddateable
+ if (EndDateable.class.isAssignableFrom(newEntity.getClass())) {
+ ((EndDateable) newEntity).setValidFrom(DateUtil.getCurrentTimeInUTC());
+ ((EndDateable) newEntity).setValidTo(null);
+ }
+ return newEntity;
+ }
+
+}
diff --git a/db/src/main/resources/log4j.xml b/db/src/main/resources/log4j.xml
new file mode 100644
index 0000000..4388d5e
--- /dev/null
+++ b/db/src/main/resources/log4j.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/db/src/test/java/de/muehlencord/shared/db/CounterEntity.java b/db/src/test/java/de/muehlencord/shared/db/CounterEntity.java
new file mode 100644
index 0000000..4729025
--- /dev/null
+++ b/db/src/test/java/de/muehlencord/shared/db/CounterEntity.java
@@ -0,0 +1,94 @@
+package de.muehlencord.shared.db;
+
+import java.io.Serializable;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ *
+ * @author joern.muehlencord
+ */
+@Entity
+@Table(name = "counter")
+@NamedQueries({
+ @NamedQuery(name = "CounterEntity.findAll", query = "SELECT c FROM CounterEntity c")
+ , @NamedQuery(name = "CounterEntity.findByCounterKey", query = "SELECT c FROM CounterEntity c WHERE c.counterKey = :counterKey")
+ , @NamedQuery(name = "CounterEntity.findByCounterDefinition", query = "SELECT c FROM CounterEntity c WHERE c.counterDefinition = :counterDefinition")})
+public class CounterEntity implements Serializable {
+
+ private static final long serialVersionUID = -5104103828013760003L;
+
+
+ @Id
+ @Basic(optional = false)
+ @NotNull
+ @Size(min = 1, max = 100)
+ @Column(name = "counter_key")
+ private String counterKey;
+ @Basic(optional = false)
+ @NotNull
+ @Size(min = 1, max = 100)
+ @Column(name = "counter_definition")
+ private String counterDefinition;
+
+ public CounterEntity() {
+ }
+
+ public CounterEntity(String counterKey) {
+ this.counterKey = counterKey;
+ }
+
+ public CounterEntity(String counterKey, String counterDefinition) {
+ this.counterKey = counterKey;
+ this.counterDefinition = counterDefinition;
+ }
+
+ public String getCounterKey() {
+ return counterKey;
+ }
+
+ public void setCounterKey(String counterKey) {
+ this.counterKey = counterKey;
+ }
+
+ public String getCounterDefinition() {
+ return counterDefinition;
+ }
+
+ public void setCounterDefinition(String counterDefinition) {
+ this.counterDefinition = counterDefinition;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += (counterKey != null ? counterKey.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ // TODO: Warning - this method won't work in the case the id fields are not set
+ if (!(object instanceof CounterEntity)) {
+ return false;
+ }
+ CounterEntity other = (CounterEntity) object;
+ if ((this.counterKey == null && other.counterKey != null) || (this.counterKey != null && !this.counterKey.equals(other.counterKey))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "de.muehlencord.office.entity.core.CounterEntity[ counterKey=" + counterKey + " ]";
+ }
+
+}
diff --git a/db/src/test/java/de/muehlencord/shared/db/EntityUtilTest.java b/db/src/test/java/de/muehlencord/shared/db/EntityUtilTest.java
new file mode 100644
index 0000000..5830521
--- /dev/null
+++ b/db/src/test/java/de/muehlencord/shared/db/EntityUtilTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2019 joern.muehlencord.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package de.muehlencord.shared.db;
+
+import java.lang.reflect.Field;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ *
+ * @author joern.muehlencord
+ */
+public class EntityUtilTest {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(EntityUtilTest.class);
+
+ @Test
+ public void testGetId() {
+ Field idField = EntityUtil.getIdField(CounterEntity.class);
+ assertNotNull(idField);
+ assertEquals("counterKey", idField.getName());
+ }
+
+ @Test
+ public void testSetIdNull() throws IllegalArgumentException, IllegalAccessException, ControllerException {
+ CounterEntity counter = new CounterEntity();
+ counter.setCounterDefinition("counterDefinitionValue");
+ counter.setCounterKey("counterKeyValue");
+ LOGGER.info("Counter after creation: {}", counter.toString());
+
+ Field idField = EntityUtil.getIdField(CounterEntity.class);
+
+ assertNotNull(idField);
+
+ assertEquals("counterKey", idField.getName());
+// assertEquals("counterKeyValue", idField.get(counter));
+ counter = EntityUtil.setIdValue(counter, null);
+// assertNull (idField.get (counter));
+ assertNull (counter.getCounterKey());
+
+ LOGGER.info("Counter after update: {}", counter.toString());
+
+
+ }
+
+}
diff --git a/db/src/test/java/de/muehlencord/shared/db/TestEntity.java b/db/src/test/java/de/muehlencord/shared/db/TestEntity.java
new file mode 100644
index 0000000..64c6ab4
--- /dev/null
+++ b/db/src/test/java/de/muehlencord/shared/db/TestEntity.java
@@ -0,0 +1,214 @@
+package de.muehlencord.shared.db;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.UUID;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.NamedQueries;
+import javax.persistence.NamedQuery;
+import javax.persistence.Table;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ *
+ * @author joern.muehlencord
+ */
+@Entity
+@Table(name = "address")
+@NamedQueries({
+ @NamedQuery(name = "AddressEntity.findAll", query = "SELECT a FROM AddressEntity a"),
+ @NamedQuery(name = "AddressEntity.findByStreet", query = "SELECT a FROM AddressEntity a WHERE a.street = :street"),
+ @NamedQuery(name = "AddressEntity.findByPostalArea", query = "SELECT a FROM AddressEntity a WHERE a.postalArea = :postalArea"),
+ @NamedQuery(name = "AddressEntity.findByCity", query = "SELECT a FROM AddressEntity a WHERE a.city = :city"),
+ @NamedQuery(name = "AddressEntity.findByValidFrom", query = "SELECT a FROM AddressEntity a WHERE a.validFrom = :validFrom"),
+ @NamedQuery(name = "AddressEntity.findByValidTo", query = "SELECT a FROM AddressEntity a WHERE a.validTo = :validTo")})
+public class TestEntity implements Serializable, Auditable, EndDateable {
+
+ private static final long serialVersionUID = 1L;
+ @Id
+ @Basic(optional = false)
+ @NotNull
+ @Column(name = "id")
+ @GeneratedValue(generator = "uuid2")
+ private UUID id;
+ @Basic(optional = false)
+ @NotNull
+ @Size(min = 1, max = 200)
+ @Column(name = "street")
+ private String street;
+ @Size(max = 10)
+ @Column(name = "street_number")
+ private String streetNumber;
+ @Basic(optional = false)
+ @NotNull
+ @Size(min = 1, max = 10)
+ @Column(name = "postal_area")
+ private String postalArea;
+ @Basic(optional = false)
+ @NotNull
+ @Size(min = 1, max = 50)
+ @Column(name = "city")
+ private String city;
+ @Column(name = "government_district")
+ private String governmentDistrict;
+ @Min(value = -90)
+ @Max(value = 90)
+ @Column(name = "latitude")
+ private Double latitude;
+ @Min(value = -180)
+ @Max(value = 180)
+ @Column(name = "longitude")
+ private Double longitude;
+ @Column(name = "valid_from")
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date validFrom;
+ @Column(name = "valid_to")
+ @Temporal(TemporalType.TIMESTAMP)
+ private Date validTo;
+ @Embedded
+ private Audit audit;
+
+ public TestEntity() {
+ // empty constructor required for JPA
+ }
+
+ public UUID getId() {
+ return id;
+ }
+
+ public String getIdString() {
+ if (id == null) {
+ return "unknown";
+ } else {
+ return id.toString();
+ }
+ }
+
+ public void setId(UUID id) {
+ this.id = id;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getStreetNumber() {
+ return streetNumber;
+ }
+
+ public void setStreetNumber(String streetNumber) {
+ this.streetNumber = streetNumber;
+ }
+
+ public String getPostalArea() {
+ return postalArea;
+ }
+
+ public void setPostalArea(String postalArea) {
+ this.postalArea = postalArea;
+ }
+
+ public String getGovernmentDistrict() {
+ return governmentDistrict;
+ }
+
+ public void setGovernmentDistrict(String governmentDistrict) {
+ this.governmentDistrict = governmentDistrict;
+ }
+
+ public Double getLatitude() {
+ return latitude;
+ }
+
+ public void setLatitude(Double latitude) {
+ this.latitude = latitude;
+ }
+
+ public Double getLongitude() {
+ return longitude;
+ }
+
+ public void setLongitude(Double longitude) {
+ this.longitude = longitude;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ @Override
+ public Date getValidFrom() {
+ return validFrom;
+ }
+
+ @Override
+ public void setValidFrom(Date validFrom) {
+ this.validFrom = validFrom;
+ }
+
+ @Override
+ public Date getValidTo() {
+ return validTo;
+ }
+
+ @Override
+ public void setValidTo(Date validTo) {
+ this.validTo = validTo;
+ }
+
+ @Override
+ public Audit getAudit() {
+ return audit;
+ }
+
+ @Override
+ public void setAudit(Audit audit) {
+ this.audit = audit;
+ }
+
+
+ @Override
+ public int hashCode() {
+ int hash = 0;
+ hash += (id != null ? id.hashCode() : 0);
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ // TODO: Warning - this method won't work in the case the id fields are not set
+ if (!(object instanceof TestEntity)) {
+ return false;
+ }
+ TestEntity other = (TestEntity) object;
+ if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "de.muehlencord.office.entity.party.AddressEntity[ id=" + id + " ]";
+ }
+
+
+}
diff --git a/pom.xml b/pom.xml
index 500a627..f60d9ea 100644
--- a/pom.xml
+++ b/pom.xml
@@ -78,7 +78,25 @@
junit
4.12
test
-
+
+
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.3.1
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-params
+ 5.3.1
+ test
+
+
+ org.junit.jupiter
+ junit-jupiter-engine
+ 5.3.1
+ test
+
org.mockito
mockito-core
@@ -108,7 +126,7 @@
org.slf4j
slf4j-api
- 1.7.25
+ 1.7.26
org.slf4j