Reputation: 35
I need to find a way how to merge two (or more) JSON objects into a single JSON object without JSON arrays.
There's code example:
public static void mergeJSONs() {
JSONObject jsonObject1 = new JSONObject("{\"1level1\":{\"1level2\":{\"1label1\":\"1value1\"}}}");
JSONObject jsonObject2 = new JSONObject("{\"1level1\":{\"1level2\":{\"1label2\":\"1value2\"}}}");
JSONObject jsonObject3 = new JSONObject("{\"2level1\":{\"2level2\":{\"2level3\":{\"2label1\":\"2value1\"}}}}");
JSONObject jsonObject4 = new JSONObject("{\"2level1\":{\"2level2\":{\"2label2\":\"2value2\"}}}");
JSONObject combined = new JSONObject();
combined.put("strings", jsonObject1);
combined.put("strings", jsonObject2);
combined.put("strings", jsonObject3);
combined.put("strings", jsonObject4);
System.out.println(combined.toString());
}
Output for this code:
{"strings":{"2level1":{"2level2":{"2label2":"2value2"}}}}
Expected output:
{
"strings":{
"1level1":{
"1level2":{
"1label1":"1value1",
"1label2":"1value2"
}
},
"2level1":{
"2level2":{
"2level3":{
"2label1":"2value1"
},
"2label2":"2value2"
}
}
}
}
or in one line:
{"strings":{"1level1":{"1level2":{"1label1":"1value1","1label2":"1value2"}},"2level1":{"2level2":{"2level3":{"2label1":"2value1"},"2label2":"2value2"}}}}
The thing is that I will never know the names of the JSON objects and how deep will this JSON be in the end as this will be used to convert files, so I am not able to create POJO for this.
Currently I'm using org.json library for this but if there is an easy way how to do that with other libraries - it works for me as well.
Library:
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20180813</version>
</dependency>
UPDATE #1: Those objects are provided just for example, in reality JSONs will be larger and deeper. Problem is that I will never know how deep and which keys matches in JSON. So here recursive method is needed which would go through both object until there is any key that matches and one of object doesn't contain that key then all the nested objects should be merged to that one.
UPDATE #2: Updated sample code and expected output to make image more clear
Upvotes: 1
Views: 508
Reputation: 5326
I prefer and recommend use Gson from Google:
The last release is 2.8.6 from Oct of 2019:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.6</version>
</dependency>
Always check last version on Maven Central Repository:
Example:
public static void mergeJSONs() {
String JSON1 = "{\"1level1\":{\"1level2\":{\"1label1\":\"1value1\"}}}";
String JSON2 = "{\"1level1\":{\"1level2\":{\"1label2\":\"1value2\"}}}";
String JSON3 = "{\"2level1\":{\"2level2\":{\"2level3\":{\"2label1\":\"2value1\"}}}}";
String JSON4 = "{\"2level1\":{\"2level2\":{\"2label2\":\"2value2\"}}}";
String finalJson = organizeJson(JSON1, JSON2, JSON3, JSON4);
System.out.println(finalJson);
}
The method can receive a list of json payloads, add a root element and merge:
public String organizeJson(String... jsonList) throws Exception {
JsonObject jsonObj = null;
Gson gson = new GsonBuilder().setPrettyPrinting().create();
for (String json : jsonList) {
if (jsonObj != null) {
jsonObj = jsonMerge(jsonObj, gson.fromJson(json, JsonObject.class));
} else {
jsonObj = gson.fromJson(json, JsonObject.class);
}
}
JsonObject jsonStringsRoot = new JsonObject();
/* Add "strings" as root element */
jsonStringsRoot.add("strings", jsonObj);
return gson.toJson(jsonStringsRoot);
}
Method using recursive call to find the last level on nested objects (deep merge):
public static JsonObject jsonMerge(JsonObject jsonA, JsonObject jsonB) throws Exception {
for (Map.Entry<String, JsonElement> sourceEntry : jsonA.entrySet()) {
String key = sourceEntry.getKey();
JsonElement value = sourceEntry.getValue();
if (!jsonB.has(key)) {
if (!value.isJsonNull()) {
jsonB.add(key, value);
}
} else {
if (!value.isJsonNull()) {
if (value.isJsonObject()) {
jsonMerge(value.getAsJsonObject(), jsonB.get(key).getAsJsonObject());
} else {
jsonB.add(key, value);
}
} else {
jsonB.remove(key);
}
}
}
return jsonB;
}
Upvotes: 1