Skip to content

Commit 59add92

Browse files
authored
Merge pull request #153 from tsurdilo/addjsonmerge
adding some json manipulation util methods
2 parents 5501a9e + 706ad5f commit 59add92

File tree

2 files changed

+180
-10
lines changed

2 files changed

+180
-10
lines changed

utils/src/main/java/io/serverlessworkflow/utils/WorkflowUtils.java

+83-10
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@
1515
*/
1616
package io.serverlessworkflow.utils;
1717

18+
import com.fasterxml.jackson.databind.JsonNode;
19+
import com.fasterxml.jackson.databind.ObjectMapper;
20+
import com.fasterxml.jackson.databind.node.ArrayNode;
21+
import com.fasterxml.jackson.databind.node.ObjectNode;
1822
import io.serverlessworkflow.api.Workflow;
1923
import io.serverlessworkflow.api.actions.Action;
2024
import io.serverlessworkflow.api.branches.Branch;
@@ -157,7 +161,7 @@ public static List<EventDefinition> getWorkflowProducedEvents(Workflow workflow)
157161
*
158162
* @return Returns {@code List<EventDefinition>}
159163
*/
160-
private static List<EventDefinition> getWorkflowEventDefinitions(
164+
public static List<EventDefinition> getWorkflowEventDefinitions(
161165
Workflow workflow, EventDefinition.Kind eventKind) {
162166
if (!hasStates(workflow)) {
163167
return null;
@@ -174,7 +178,7 @@ private static List<EventDefinition> getWorkflowEventDefinitions(
174178
}
175179

176180
/** Returns a list of unique event names from workflow states */
177-
private static List<String> getUniqueWorkflowEventsFromStates(Workflow workflow) {
181+
public static List<String> getUniqueWorkflowEventsFromStates(Workflow workflow) {
178182
List<String> eventReferences = new ArrayList<>();
179183

180184
for (State state : workflow.getStates()) {
@@ -351,7 +355,7 @@ public static long getNumOfEndStates(Workflow workflow) {
351355
}
352356
}
353357

354-
private static List<Action> getActionsWhichUsesFunctionDefinition(
358+
public static List<Action> getActionsWhichUsesFunctionDefinition(
355359
Workflow workflow, String functionDefinitionName) {
356360
List<Action> actions = new ArrayList<>();
357361
for (State state : workflow.getStates()) {
@@ -419,23 +423,23 @@ private static List<Action> getActionsWhichUsesFunctionDefinition(
419423
return actions;
420424
}
421425

422-
private static boolean checkIfActionUsesFunctionDefinition(
426+
public static boolean checkIfActionUsesFunctionDefinition(
423427
String functionDefinitionName, Action action) {
424428
return action != null
425429
&& action.getFunctionRef() != null
426430
&& action.getFunctionRef().getRefName() != null
427431
&& action.getFunctionRef().getRefName().equals(functionDefinitionName);
428432
}
429433

430-
private static boolean hasFunctionDefs(Workflow workflow, String functionDefinitionName) {
434+
public static boolean hasFunctionDefs(Workflow workflow, String functionDefinitionName) {
431435
if (!hasFunctionDefs(workflow)) return false;
432436
List<FunctionDefinition> functionDefs = workflow.getFunctions().getFunctionDefs();
433437
return functionDefs.stream()
434438
.anyMatch(
435439
functionDefinition -> functionDefinition.getName().equals(functionDefinitionName));
436440
}
437441

438-
private static FunctionRef getFunctionRefFromAction(Workflow workflow, String action) {
442+
public static FunctionRef getFunctionRefFromAction(Workflow workflow, String action) {
439443
if (!hasStates(workflow)) return null;
440444

441445
for (State state : workflow.getStates()) {
@@ -513,28 +517,28 @@ private static FunctionRef getFunctionRefFromAction(Workflow workflow, String ac
513517
return null;
514518
}
515519

516-
private static boolean hasFunctionDefs(Workflow workflow) {
520+
public static boolean hasFunctionDefs(Workflow workflow) {
517521
return workflow != null
518522
&& workflow.getFunctions() != null
519523
&& workflow.getFunctions().getFunctionDefs() != null
520524
&& !workflow.getFunctions().getFunctionDefs().isEmpty();
521525
}
522526

523527
/** Returns true if workflow has states, otherwise false */
524-
private static boolean hasStates(Workflow workflow) {
528+
public static boolean hasStates(Workflow workflow) {
525529
return workflow != null && workflow.getStates() != null && !workflow.getStates().isEmpty();
526530
}
527531

528532
/** Returns true if workflow has events definitions, otherwise false */
529-
private static boolean hasEventDefs(Workflow workflow) {
533+
public static boolean hasEventDefs(Workflow workflow) {
530534
return workflow != null
531535
&& workflow.getEvents() != null
532536
&& workflow.getEvents().getEventDefs() != null
533537
&& !workflow.getEvents().getEventDefs().isEmpty();
534538
}
535539

536540
/** Gets event refs of an action */
537-
private static List<String> getActionEvents(Action action) {
541+
public static List<String> getActionEvents(Action action) {
538542
List<String> actionEvents = new ArrayList<>();
539543

540544
if (action != null && action.getEventRef() != null) {
@@ -548,4 +552,73 @@ private static List<String> getActionEvents(Action action) {
548552

549553
return actionEvents;
550554
}
555+
556+
/**
557+
* Merges two JsonNode
558+
*
559+
* @param mainNode
560+
* @param updateNode
561+
* @return merged JsonNode
562+
*/
563+
public static JsonNode mergeNodes(JsonNode mainNode, JsonNode updateNode) {
564+
565+
Iterator<String> fieldNames = updateNode.fieldNames();
566+
while (fieldNames.hasNext()) {
567+
568+
String fieldName = fieldNames.next();
569+
JsonNode jsonNode = mainNode.get(fieldName);
570+
// if field exists and is an embedded object
571+
if (jsonNode != null && jsonNode.isObject()) {
572+
mergeNodes(jsonNode, updateNode.get(fieldName));
573+
} else {
574+
if (mainNode instanceof ObjectNode) {
575+
// Overwrite field
576+
JsonNode value = updateNode.get(fieldName);
577+
((ObjectNode) mainNode).put(fieldName, value);
578+
}
579+
}
580+
}
581+
582+
return mainNode;
583+
}
584+
585+
/**
586+
* Adds node as field
587+
*
588+
* @param mainNode
589+
* @param toAddNode
590+
* @param fieldName
591+
* @return original, main node with field added
592+
*/
593+
public static JsonNode addNode(JsonNode mainNode, JsonNode toAddNode, String fieldName) {
594+
((ObjectNode) mainNode).put(fieldName, toAddNode);
595+
return mainNode;
596+
}
597+
598+
/**
599+
* Adds array with name
600+
*
601+
* @param mainNode
602+
* @param toAddArray
603+
* @param arrayName
604+
* @return original, main node with array added
605+
*/
606+
public static JsonNode addArray(JsonNode mainNode, ArrayNode toAddArray, String arrayName) {
607+
((ObjectNode) mainNode).put(arrayName, toAddArray);
608+
return mainNode;
609+
}
610+
611+
/**
612+
* Adds a object field
613+
*
614+
* @param mainNode
615+
* @param toAddValue
616+
* @param fieldName
617+
* @return original, main node with field added
618+
*/
619+
public static JsonNode addFieldValue(JsonNode mainNode, Object toAddValue, String fieldName) {
620+
ObjectMapper mapper = new ObjectMapper();
621+
((ObjectNode) mainNode).put(fieldName, mapper.valueToTree(toAddValue));
622+
return mainNode;
623+
}
551624
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2020-Present The Serverless Workflow Specification Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.serverlessworkflow.util;
17+
18+
import static org.junit.jupiter.api.Assertions.*;
19+
20+
import com.fasterxml.jackson.databind.JsonNode;
21+
import com.fasterxml.jackson.databind.ObjectMapper;
22+
import com.fasterxml.jackson.databind.node.ArrayNode;
23+
import io.serverlessworkflow.utils.WorkflowUtils;
24+
import org.junit.jupiter.api.Test;
25+
26+
public class JsonManipulationTest {
27+
private static final ObjectMapper mapper = new ObjectMapper();
28+
29+
@Test
30+
public void testAddFieldValue() throws Exception {
31+
String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
32+
JsonNode mainNode = mapper.readTree(mainString);
33+
String toAddString = "v3";
34+
35+
JsonNode added = WorkflowUtils.addFieldValue(mainNode, toAddString, "k3");
36+
37+
assertNotNull(added);
38+
assertEquals("v3", added.get("k3").asText());
39+
}
40+
41+
@Test
42+
public void testAddNode() throws Exception {
43+
String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
44+
JsonNode mainNode = mapper.readTree(mainString);
45+
String toAddString = "{\"k3\":\"v3\"}";
46+
JsonNode toAddNode = mapper.readTree(toAddString);
47+
48+
JsonNode added = WorkflowUtils.addNode(mainNode, toAddNode, "newnode");
49+
50+
assertNotNull(added);
51+
assertEquals("v3", added.get("newnode").get("k3").asText());
52+
}
53+
54+
@Test
55+
public void testAddArray() throws Exception {
56+
String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
57+
JsonNode mainNode = mapper.readTree(mainString);
58+
String toAddString = "[\"a\", \"b\"]";
59+
JsonNode toAddNode = mapper.readTree(toAddString);
60+
61+
JsonNode added = WorkflowUtils.addArray(mainNode, (ArrayNode) toAddNode, "newarray");
62+
63+
assertNotNull(added);
64+
assertNotNull(added.get("newarray"));
65+
assertEquals(2, added.get("newarray").size());
66+
assertEquals("a", added.get("newarray").get(0).asText());
67+
assertEquals("b", added.get("newarray").get(1).asText());
68+
}
69+
70+
@Test
71+
public void testMergeNodes() throws Exception {
72+
String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
73+
JsonNode mainNode = mapper.readTree(mainString);
74+
String toMergeString = "{\"k3\":\"v3\",\"k4\":\"v4\"}";
75+
JsonNode toMergeNode = mapper.readTree(toMergeString);
76+
77+
JsonNode merged = WorkflowUtils.mergeNodes(mainNode, toMergeNode);
78+
79+
assertNotNull(merged);
80+
assertEquals("v3", merged.get("k3").asText());
81+
assertEquals("v4", merged.get("k4").asText());
82+
}
83+
84+
@Test
85+
public void testMergeWithOverwrite() throws Exception {
86+
String mainString = "{\"k1\":\"v1\",\"k2\":\"v2\"}";
87+
JsonNode mainNode = mapper.readTree(mainString);
88+
String toMergeString = "{\"k2\":\"v2new\",\"k3\":\"v3\"}";
89+
JsonNode toMergeNode = mapper.readTree(toMergeString);
90+
91+
JsonNode merged = WorkflowUtils.mergeNodes(mainNode, toMergeNode);
92+
93+
assertNotNull(merged);
94+
assertEquals("v2new", merged.get("k2").asText());
95+
assertEquals("v3", merged.get("k3").asText());
96+
}
97+
}

0 commit comments

Comments
 (0)