removed dependencies from FlowableModelTestUtils, removed JsonUtils

This commit is contained in:
Andreas Isler
2026-06-12 16:31:19 +02:00
parent d183153660
commit f5f495567c
3 changed files with 60 additions and 136 deletions
+7 -6
View File
@@ -51,6 +51,11 @@
<artifactId>postgresql</artifactId> <artifactId>postgresql</artifactId>
<scope>runtime</scope> <scope>runtime</scope>
</dependency> </dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Flowable Inspect --> <!-- Flowable Inspect -->
<!-- ======= --> <!-- ======= -->
@@ -66,20 +71,17 @@
<artifactId>spring-boot-starter-test</artifactId> <artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency> <dependency>
<groupId>com.github.wnameless.json</groupId> <groupId>com.github.wnameless.json</groupId>
<artifactId>json-flattener</artifactId> <artifactId>json-flattener</artifactId>
<version>0.16.6</version> <version>0.16.6</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.icegreen</groupId> <groupId>com.icegreen</groupId>
<artifactId>greenmail</artifactId> <artifactId>greenmail</artifactId>
<version>2.1.8</version> <version>2.1.8</version>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>org.apache.poi</groupId>
@@ -87,7 +89,6 @@
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
<build> <build>
@@ -1,107 +0,0 @@
package com.customer.work.service;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.github.wnameless.json.flattener.JsonFlattener;
import com.github.wnameless.json.unflattener.JsonUnflattener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;
@Component
public class JsonUtils {
protected static final Logger LOGGER = LoggerFactory.getLogger(JsonUtils.class);
protected final ObjectMapper objectMapper;
protected final JavaTimeModule javaTimeModule;
public JsonUtils(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
this.javaTimeModule = new JavaTimeModule();
// Enable ObjectMapper for handling Instant as string
this.objectMapper.registerModule(javaTimeModule);
this.objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
public JsonNode convertListToJsonNode(List<Object> list) {
return objectMapper.valueToTree(list);
}
public JsonNode convertMapToJsonNode(Map<String, Object> map) {
return objectMapper.valueToTree(map);
}
public Map<String, Object> convertJsonNodeToMap(JsonNode jsonNode) {
return objectMapper.convertValue(jsonNode, new TypeReference<>() {});
}
public Map<String, Object> flatten(Object payload) {
try {
return JsonFlattener.flattenAsMap(objectMapper.writeValueAsString(payload));
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public Map<String, Object> unflatten(Map<String, Object> flatVars) {
try {
return objectMapper.readValue(JsonUnflattener.unflatten(flatVars), new TypeReference<>() {});
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
public JsonNode convertJsonStringToJsonNode(String jsonString) {
try {
return objectMapper.readTree(jsonString);
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public Map<String, Object> convertObjectNodeToMap(ObjectNode objectNode) {
return objectMapper.convertValue(objectNode, new TypeReference<>() {});
}
public ObjectNode getEmptyObjectNode() {
return objectMapper.createObjectNode();
}
public ObjectNode loadObjectNodeFromFile(String path) {
try {
return (ObjectNode) this.objectMapper.readTree(new File(path));
} catch (IOException e) {
LOGGER.debug(e.getMessage());
return null;
}
}
public ArrayNode convertObjectToArrayNode(Object object) {
if (object == null) {
LOGGER.debug("{}: Argument is null", this.getClass().getName());
return null;
}
String obyTypeName = object.getClass().getName();
if (obyTypeName.equals("java.util.Collections$EmptyList") || obyTypeName.equals("java.util.ArrayList")) {
return objectMapper.convertValue(object, ArrayNode.class);
} else if (obyTypeName.equals("com.fasterxml.jackson.databind.node.ArrayNode")) {
return (ArrayNode) object;
} else {
LOGGER.debug("{}: {} is not implemented}", this.getClass().getName(), obyTypeName);
return null;
}
}
}
@@ -1,13 +1,19 @@
package com.customer.work.model; package com.customer.work.model;
import com.customer.work.service.JsonUtils; import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.flowable.audit.api.AuditService; import com.flowable.audit.api.AuditService;
import com.flowable.audit.api.runtime.AuditInstance; import com.flowable.audit.api.runtime.AuditInstance;
import com.flowable.core.spring.security.SecurityUtils; import com.flowable.core.spring.security.SecurityUtils;
import com.flowable.platform.service.task.CompleteFormRepresentation; import com.flowable.platform.service.task.CompleteFormRepresentation;
import com.flowable.platform.service.task.PlatformTaskService; import com.flowable.platform.service.task.PlatformTaskService;
import com.github.wnameless.json.flattener.JsonFlattener;
import com.github.wnameless.json.unflattener.JsonUnflattener;
import jakarta.mail.Address; import jakarta.mail.Address;
import org.assertj.core.api.Assertions; import org.assertj.core.api.Assertions;
import org.flowable.bpmn.model.*; import org.flowable.bpmn.model.*;
@@ -37,7 +43,6 @@ import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestClient; import org.springframework.web.client.RestClient;
import java.io.*; import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -51,11 +56,11 @@ public class FlowableModelTestUtils {
protected final TaskService taskService; protected final TaskService taskService;
protected final PlatformTaskService platformTaskService; protected final PlatformTaskService platformTaskService;
protected final ManagementService managementService; protected final ManagementService managementService;
protected final JsonUtils jsonUtils;
protected final FlowableExcelMapper flowableExcelMapper; protected final FlowableExcelMapper flowableExcelMapper;
protected static final Logger logger = LoggerFactory.getLogger(FlowableModelTestUtils.class); protected static final Logger logger = LoggerFactory.getLogger(FlowableModelTestUtils.class);
protected final TestMailServer testMailServer; protected final TestMailServer testMailServer;
protected final AuditService auditService; protected final AuditService auditService;
protected final ObjectMapper objectMapper = new ObjectMapper();
public static final String TENANT_ID = null; public static final String TENANT_ID = null;
@@ -72,7 +77,6 @@ public class FlowableModelTestUtils {
TaskService taskService, TaskService taskService,
PlatformTaskService platformTaskService, PlatformTaskService platformTaskService,
ManagementService managementService, ManagementService managementService,
JsonUtils jsonUtils,
FlowableExcelMapper flowableExcelMapper, FlowableExcelMapper flowableExcelMapper,
TestMailServer testMailServer, TestMailServer testMailServer,
AuditService auditService) { AuditService auditService) {
@@ -81,10 +85,36 @@ public class FlowableModelTestUtils {
this.taskService = taskService; this.taskService = taskService;
this.platformTaskService = platformTaskService; this.platformTaskService = platformTaskService;
this.managementService = managementService; this.managementService = managementService;
this.jsonUtils = jsonUtils;
this.flowableExcelMapper = flowableExcelMapper; this.flowableExcelMapper = flowableExcelMapper;
this.testMailServer = testMailServer; this.testMailServer = testMailServer;
this.auditService = auditService; this.auditService = auditService;
// Enable ObjectMapper for handling Instant as string
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
protected Map<String, Object> convertJsonNodeToMap(JsonNode jsonNode) {
return objectMapper.convertValue(jsonNode, new TypeReference<>() {});
}
protected JsonNode convertMapToJsonNode(Map<String, Object> map) {
return objectMapper.valueToTree(map);
}
protected Map<String, Object> flatten(Object payload) {
try {
return JsonFlattener.flattenAsMap(objectMapper.writeValueAsString(payload));
} catch (JsonProcessingException e) {
throw new UncheckedIOException("Cannot flatten: " + payload, e);
}
}
protected Map<String, Object> unflatten(Map<String, Object> flatVars) {
try {
return objectMapper.readValue(JsonUnflattener.unflatten(flatVars), new TypeReference<>() {});
} catch (JsonProcessingException e) {
throw new UncheckedIOException("Cannot unflatten: " + flatVars, e);
}
} }
public void checkAndAssertAuditRecord(Map<String, Object> map, int auditNumber, String hint, String message, String category, String type) { public void checkAndAssertAuditRecord(Map<String, Object> map, int auditNumber, String hint, String message, String category, String type) {
@@ -270,7 +300,7 @@ public class FlowableModelTestUtils {
} }
public ObjectNode testJsonExcelRow(String path, JsonNode row) { public ObjectNode testJsonExcelRow(String path, JsonNode row) {
ObjectNode vars = jsonUtils.getEmptyObjectNode(); ObjectNode vars = objectMapper.createObjectNode();
JsonNode rootParam = row.get("root"); JsonNode rootParam = row.get("root");
if (rootParam != null) { if (rootParam != null) {
for (Map.Entry<String, JsonNode> rootVar : rootParam.properties()) { for (Map.Entry<String, JsonNode> rootVar : rootParam.properties()) {
@@ -300,14 +330,14 @@ public class FlowableModelTestUtils {
logger.info("TestExcelRow file={} id={} rootParam={} inParam={} outParam={} timer={} test={} audit={} email={} ", logger.info("TestExcelRow file={} id={} rootParam={} inParam={} outParam={} timer={} test={} audit={} email={} ",
path, idParam, rootParam, inParam, outParam, timerCount, test, auditRecordCount, emailCount); path, idParam, rootParam, inParam, outParam, timerCount, test, auditRecordCount, emailCount);
Assertions.assertThat(idParam).as("Column 'id' missing in row of %s", path).isNotNull(); Assertions.assertThat(idParam).as("Column 'id' missing in row of %s", path).isNotNull();
ObjectNode processIds = createRootTestProcessInstance(idParam.asText(), jsonUtils.convertJsonNodeToMap(vars)); ObjectNode processIds = createRootTestProcessInstance(idParam.asText(), convertJsonNodeToMap(vars));
for (int i = 0; i < timerCount; i++) { for (int i = 0; i < timerCount; i++) {
executeTimer(processIds.get(TEST_PROCESS_ID).asText()); executeTimer(processIds.get(TEST_PROCESS_ID).asText());
} }
ObjectNode result = jsonUtils.getEmptyObjectNode(); ObjectNode result = objectMapper.createObjectNode();
Map<String, Object> rootProcessPayload = getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText()); Map<String, Object> rootProcessPayload = getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText());
JsonNode root = jsonUtils.convertMapToJsonNode(rootProcessPayload); JsonNode root = convertMapToJsonNode(rootProcessPayload);
if (root != null) { if (root != null) {
Assertions.assertThat(isSubset(root, test)) Assertions.assertThat(isSubset(root, test))
.withFailMessage(System.lineSeparator() + "test :" + test + System.lineSeparator() + "root :" + root).isTrue(); .withFailMessage(System.lineSeparator() + "test :" + test + System.lineSeparator() + "root :" + root).isTrue();
@@ -316,12 +346,12 @@ public class FlowableModelTestUtils {
if (auditRecordCount != null) { if (auditRecordCount != null) {
List<AuditInstance> auditTrail = getAuditTrail(); List<AuditInstance> auditTrail = getAuditTrail();
Assertions.assertThat(auditTrail.size()).as("Invalid audit trail size: %s", auditTrail.size()).isEqualTo(auditRecordCount); Assertions.assertThat(auditTrail.size()).as("Invalid audit trail size: %s", auditTrail.size()).isEqualTo(auditRecordCount);
result.set("auditTrail", jsonUtils.convertListToJsonNode(Collections.singletonList(auditTrail))); result.set("auditTrail", objectMapper.valueToTree(Collections.singletonList(auditTrail)));
} }
if (emailCount != null) { if (emailCount != null) {
List<EmailDto> emailList = getMailList(); List<EmailDto> emailList = getMailList();
Assertions.assertThat(emailList.size()).as("Invalid number of emails: %s", emailList.size()).isEqualTo(emailCount); Assertions.assertThat(emailList.size()).as("Invalid number of emails: %s", emailList.size()).isEqualTo(emailCount);
result.set("emails", jsonUtils.convertListToJsonNode(Collections.singletonList(emailList))); result.set("emails", objectMapper.valueToTree(Collections.singletonList(emailList)));
} }
return result; return result;
} }
@@ -362,9 +392,9 @@ public class FlowableModelTestUtils {
Map<String, Object> result = new LinkedHashMap<>(); Map<String, Object> result = new LinkedHashMap<>();
Map<String, Object> rootProcessPayload = getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText()); Map<String, Object> rootProcessPayload = getHistProcessPayload(processIds.get(FlowableModelTestUtils.ROOT_PROCESS_ID).asText());
JsonNode root = jsonUtils.convertMapToJsonNode(rootProcessPayload); JsonNode root = convertMapToJsonNode(rootProcessPayload);
if (root != null) { if (root != null) {
Assertions.assertThat(isSubset(root, jsonUtils.convertMapToJsonNode(test))) Assertions.assertThat(isSubset(root, convertMapToJsonNode(test)))
.withFailMessage(System.lineSeparator() + "test :" + test + System.lineSeparator() + "root :" + root).isTrue(); .withFailMessage(System.lineSeparator() + "test :" + test + System.lineSeparator() + "root :" + root).isTrue();
result.put("root", rootProcessPayload); result.put("root", rootProcessPayload);
} }
@@ -409,7 +439,7 @@ public class FlowableModelTestUtils {
} }
public ObjectNode emptyNode() { public ObjectNode emptyNode() {
return jsonUtils.getEmptyObjectNode(); return objectMapper.createObjectNode();
} }
public Map<String, Object> emptyMap() { public Map<String, Object> emptyMap() {
@@ -417,12 +447,12 @@ public class FlowableModelTestUtils {
} }
public ObjectNode loadObjectNodeFromResources(String path) { public ObjectNode loadObjectNodeFromResources(String path) {
if (path == null || path.isEmpty()) return jsonUtils.getEmptyObjectNode(); if (path == null || path.isEmpty()) return objectMapper.createObjectNode();
try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) { try (InputStream inputStream = getClass().getClassLoader().getResourceAsStream(path)) {
if (inputStream == null) { if (inputStream == null) {
throw new IllegalArgumentException("Resource not found: " + path); throw new IllegalArgumentException("Resource not found: " + path);
} }
JsonNode jsonNode = jsonUtils.convertJsonStringToJsonNode(new String(inputStream.readAllBytes(), StandardCharsets.UTF_8)); JsonNode jsonNode = objectMapper.readTree(inputStream);
Assertions.assertThat(jsonNode).as("Resource %s is not a JSON object", path).isInstanceOf(ObjectNode.class); Assertions.assertThat(jsonNode).as("Resource %s is not a JSON object", path).isInstanceOf(ObjectNode.class);
return (ObjectNode) jsonNode; return (ObjectNode) jsonNode;
} catch (IOException e) { } catch (IOException e) {
@@ -448,9 +478,9 @@ public class FlowableModelTestUtils {
Assertions.assertThat(rootVar.getKey().startsWith("__")) Assertions.assertThat(rootVar.getKey().startsWith("__"))
.as("Root parameter '%s' in %s must not start with '__'", rootVar.getKey(), path).isFalse(); .as("Root parameter '%s' in %s must not start with '__'", rootVar.getKey(), path).isFalse();
} }
vars.putAll(jsonUtils.convertJsonNodeToMap(field.getValue())); vars.putAll(convertJsonNodeToMap(field.getValue()));
} }
case IN_PARAM, OUT_PARAM -> vars.put(key, jsonUtils.convertJsonNodeToMap(field.getValue())); case IN_PARAM, OUT_PARAM -> vars.put(key, convertJsonNodeToMap(field.getValue()));
default -> throw new IllegalArgumentException("Implicit parameter '" + key + "' in " + path default -> throw new IllegalArgumentException("Implicit parameter '" + key + "' in " + path
+ ": parameters must be declared explicitly inside " + ROOT_PARAM + ", " + IN_PARAM + " or " + OUT_PARAM); + ": parameters must be declared explicitly inside " + ROOT_PARAM + ", " + IN_PARAM + " or " + OUT_PARAM);
} }
@@ -495,9 +525,9 @@ public class FlowableModelTestUtils {
public void completeTaskWithFlatVars(String taskId, Map<String, Object> variables, String outcome) { public void completeTaskWithFlatVars(String taskId, Map<String, Object> variables, String outcome) {
Map<String, Object> taskVariables = platformTaskService.getTaskVariables(taskId); Map<String, Object> taskVariables = platformTaskService.getTaskVariables(taskId);
Map<String, Object> taskVariablesFlat = jsonUtils.flatten(taskVariables); Map<String, Object> taskVariablesFlat = flatten(taskVariables);
taskVariablesFlat.putAll(variables); taskVariablesFlat.putAll(variables);
Map<String, Object> completionVars = jsonUtils.unflatten(taskVariablesFlat); Map<String, Object> completionVars = unflatten(taskVariablesFlat);
completeTask(taskId, completionVars, outcome); completeTask(taskId, completionVars, outcome);
} }
@@ -513,7 +543,7 @@ public class FlowableModelTestUtils {
public void completeOpenTask(String taskKey, ObjectNode vars, String outcome) { public void completeOpenTask(String taskKey, ObjectNode vars, String outcome) {
Task task = getOpenTask(taskKey); Task task = getOpenTask(taskKey);
Map<String, Object> flatVars = jsonUtils.convertJsonNodeToMap(vars); Map<String, Object> flatVars = convertJsonNodeToMap(vars);
completeTaskWithFlatVars(task.getId(), flatVars, outcome); completeTaskWithFlatVars(task.getId(), flatVars, outcome);
} }
@@ -536,7 +566,7 @@ public class FlowableModelTestUtils {
public ObjectNode createRootTestProcessInstance(String testKey, Map<String, Object> variables) { public ObjectNode createRootTestProcessInstance(String testKey, Map<String, Object> variables) {
// Create root process with test process as call activity // Create root process with test process as call activity
String wrapperProcessKey = testKey + "_T"; String wrapperProcessKey = testKey + "_T";
BpmnModel bpmnModel = createWrapperTestProcessModel(testKey, (ObjectNode) jsonUtils.convertMapToJsonNode(variables)); BpmnModel bpmnModel = createWrapperTestProcessModel(testKey, (ObjectNode) convertMapToJsonNode(variables));
processEngine.getProcessEngineConfiguration() processEngine.getProcessEngineConfiguration()
.getRepositoryService() .getRepositoryService()
.createDeployment() .createDeployment()
@@ -563,7 +593,7 @@ public class FlowableModelTestUtils {
// if history level is none, testProcessId is not available // if history level is none, testProcessId is not available
testProcessId = historicTestProcessInstance != null ? historicTestProcessInstance.getId() : null; testProcessId = historicTestProcessInstance != null ? historicTestProcessInstance.getId() : null;
} }
ObjectNode rootNode = jsonUtils.getEmptyObjectNode(); ObjectNode rootNode = objectMapper.createObjectNode();
rootNode.put(ROOT_PROCESS_ID, rootProcessInstance.getProcessInstanceId()); rootNode.put(ROOT_PROCESS_ID, rootProcessInstance.getProcessInstanceId());
rootNode.put(TEST_PROCESS_ID, testProcessId); rootNode.put(TEST_PROCESS_ID, testProcessId);
return rootNode; return rootNode;