1111import java .util .LinkedHashMap ;
1212import java .util .List ;
1313import java .util .Map ;
14- import java .util .function .BiFunction ;
1514
1615public interface JsonUtils {
1716 ObjectMapper objectMapper = new ObjectMapper ();
@@ -26,27 +25,13 @@ static Object parseValue(String value) {
2625 }
2726 }
2827
29- /**
30- * update a nested value in a json object.
31- */
32- static void updateNestedValue (List <Object > args ){
33- Object currentObj = args .get (0 );
34- String [] pathParts = (String []) args .get (1 );
35- int depth = (Integer ) args .get (2 );
36- Object valueToUpdate = args .get (3 );
37-
38- updateNestedValue (currentObj , pathParts , depth , valueToUpdate );
28+ @ FunctionalInterface
29+ interface UpdateConsumer {
30+ void apply (Map <String , Object > obj , String key , Object value );
3931 }
4032
41- /**
42- * update a nested value in a json object.
43- *
44- * @param currentObj - json object to traverse
45- * @param pathParts - key at path to update
46- * @param depth - current traversal depth
47- * @param valueToUpdate - value to update
48- */
49- private static void updateNestedValue (Object currentObj , String [] pathParts , int depth , Object valueToUpdate ) {
33+ private static void traverseNestedObject (Object currentObj , String [] pathParts , int depth ,
34+ Object valueToUpdate , UpdateConsumer updateObjectFunction ) {
5035 if (currentObj == null || depth >= pathParts .length ) {
5136 return ;
5237 }
@@ -56,90 +41,80 @@ private static void updateNestedValue(Object currentObj, String[] pathParts, int
5641 String currentKey = pathParts [depth ];
5742
5843 if (depth == pathParts .length - 1 ) {
59- currentMap . put ( currentKey , valueToUpdate );
44+ updateObjectFunction . apply ( currentMap , currentKey , valueToUpdate );
6045 } else {
6146 // Continue traversing
62- currentMap .computeIfAbsent (currentKey , k -> new LinkedHashMap <>()); // Create map if not present
63- updateNestedValue (currentMap .get (currentKey ), pathParts , depth + 1 , valueToUpdate );
47+ currentMap .computeIfAbsent (currentKey ,
48+ k -> new LinkedHashMap <>()); // Create map if not present
49+ traverseNestedObject (currentMap .get (currentKey ), pathParts , depth + 1 ,
50+ valueToUpdate , updateObjectFunction );
6451 }
6552 } else if (currentObj instanceof List ) {
6653 // If the current object is a list, process each map in the list
6754 List <Object > list = (List <Object >) currentObj ;
6855 for (Object item : list ) {
6956 if (item instanceof Map ) {
70- updateNestedValue (item , pathParts , depth , valueToUpdate );
57+ traverseNestedObject (item , pathParts , depth , valueToUpdate , updateObjectFunction );
7158 }
7259 }
7360 }
7461 }
7562
76- /**
77- * append nested value to the json object.
78- */
79- static void appendNestedValue (List <Object > args ) {
80- Object currentObj = args .get (0 );
81- String [] pathParts = (String []) args .get (1 );
82- int depth = (Integer ) args .get (2 );
83- Object valueToUpdate = args .get (3 );
84-
85- appendNestedValue (currentObj , pathParts , depth , valueToUpdate , false );
86- }
63+ static String updateNestedJson (String jsonStr , List <String > pathValues , UpdateConsumer updateFieldConsumer ) {
64+ if (jsonStr == null ) {
65+ return null ;
66+ }
67+ // don't update if the list is empty, or the list is not key-value pairs
68+ if (pathValues .isEmpty ()) {
69+ return jsonStr ;
70+ }
71+ try {
72+ // Parse the JSON string into a Map
73+ Map <String , Object > jsonMap = objectMapper .readValue (jsonStr , Map .class );
74+
75+ // Iterate through the key-value pairs and update the json
76+ var iter = pathValues .iterator ();
77+ while (iter .hasNext ()) {
78+ String path = iter .next ();
79+ if (!iter .hasNext ()) {
80+ // no value provided and cannot update anything
81+ break ;
82+ }
83+ String [] pathParts = path .split ("\\ ." );
84+ Object parsedValue = parseValue (iter .next ());
8785
88- /**
89- * append nested value to the json object.
90- */
91- static void extendNestedValue (List <Object > args ) {
92- Object currentObj = args .get (0 );
93- String [] pathParts = (String []) args .get (1 );
94- int depth = (Integer ) args .get (2 );
95- Object valueToUpdate = args .get (3 );
86+ traverseNestedObject (jsonMap , pathParts , 0 , parsedValue , updateFieldConsumer );
87+ }
9688
97- appendNestedValue (currentObj , pathParts , depth , valueToUpdate , true );
89+ // Convert the updated map back to JSON
90+ return objectMapper .writeValueAsString (jsonMap );
91+ } catch (Exception e ) {
92+ return null ;
93+ }
9894 }
9995
100- /**
101- * append nested value to the json object.
102- *
103- * @param currentObj - json object to traverse
104- * @param pathParts - key at path to update
105- * @param depth - current traversal depth
106- * @param valueToAppend - value to add list
107- * @param flattenValue - if value should be flattened first
108- */
109- private static void appendNestedValue (Object currentObj , String [] pathParts , int depth , Object valueToAppend , boolean flattenValue ) {
110- if (currentObj == null || depth >= pathParts .length ) {
111- return ;
96+ static void appendObjectValue (Map <String , Object > obj , String key , Object value ) {
97+ // If it's the last key, append to the array
98+ obj .computeIfAbsent (key , k -> new ArrayList <>()); // Create list if not present
99+ Object existingValue = obj .get (key );
100+
101+ if (existingValue instanceof List ) {
102+ List <Object > list = (List <Object >) existingValue ;
103+ list .add (value );
112104 }
105+ }
113106
114- if (currentObj instanceof Map ) {
115- Map <String , Object > currentMap = (Map <String , Object >) currentObj ;
116- String currentKey = pathParts [depth ];
107+ static void extendObjectValue (Map <String , Object > obj , String key , Object value ) {
108+ // If it's the last key, append to the array
109+ obj .computeIfAbsent (key , k -> new ArrayList <>()); // Create list if not present
110+ Object existingValue = obj .get (key );
117111
118- if (depth == pathParts .length - 1 ) {
119- // If it's the last key, append to the array
120- currentMap .computeIfAbsent (currentKey , k -> new ArrayList <>()); // Create list if not present
121- Object existingValue = currentMap .get (currentKey );
122-
123- if (existingValue instanceof List ) {
124- List <Object > existingList = (List <Object >) existingValue ;
125- if (flattenValue && valueToAppend instanceof List ) {
126- existingList .addAll ((List ) valueToAppend );
127- } else {
128- existingList .add (valueToAppend );
129- }
130- }
112+ if (existingValue instanceof List ) {
113+ List <Object > existingList = (List <Object >) existingValue ;
114+ if (value instanceof List ) {
115+ existingList .addAll ((List ) value );
131116 } else {
132- // Continue traversing
133- currentMap .computeIfAbsent (currentKey , k -> new LinkedHashMap <>()); // Create map if not present
134- appendNestedValue (currentMap .get (currentKey ), pathParts , depth + 1 , valueToAppend , flattenValue );
135- }
136- } else if (currentObj instanceof List ) {
137- // If the current object is a list, process each map in the list
138- List <Object > list = (List <Object >) currentObj ;
139- for (Object item : list ) {
140- if (item instanceof Map ) {
141- appendNestedValue (item , pathParts , depth , valueToAppend , flattenValue );
142- }
117+ existingList .add (value );
143118 }
144119 }
145120 }
0 commit comments