package org.gcube.portlets.user.geoportaldataentry.server.json; import java.io.IOException; import java.util.Iterator; import java.util.Map; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; /** * This class provides methods to merge two json of any nested level into a single json. * * copied from: https://github.com/hemantsonu20/json-merge */ public class JsonMerge { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); /** * Method to merge two json objects into single json object. * *

It merges two json of any nested level into a single json following below logic.

* * *

Examples

*

Example 1

*

Source Json

*
{@code
     * {
     *   "name": "json-merge-src"
     * }
     * }
*

Target Json

*
{@code
     * {
     *   "name": "json-merge-target"
     * }
     * }
*

Output

*
{@code
     * {
     *   "name": "json-merge-src"
     * }
     * }
*

Example 2

*

Source Json

*
{@code
     * {
     *   "level1": {
     *     "key1": "SrcValue1"
     *   }
     * }
     * }
*

Target Json

*
{@code
     * {
     *   "level1": {
     *     "key1": "targetValue1",
     *     "level2": {
     *       "key2": "value2"
     *     }
     *   }
     * }
     * }
*

Output

*
{@code
     * {
     *   "level1": {
     *     "key1": "SrcValue1",
     *     "level2": {
     *       "key2": "value2"
     *     }
     *   }
     * }
     * }
* * @param srcJsonStr source json string * @param targetJsonStr target json string * @return merged json as a string */ public static String merge(String srcJsonStr, String targetJsonStr) { try { JsonNode srcNode = OBJECT_MAPPER.readTree(srcJsonStr); JsonNode targetNode = OBJECT_MAPPER.readTree(targetJsonStr); JsonNode result = merge(srcNode, targetNode); return OBJECT_MAPPER.writeValueAsString(result); } catch (IOException e) { throw new JsonMergeException("Unable to merge json", e); } } public static JsonNode merge(JsonNode srcNode, JsonNode targetNode) { // if both nodes are object node, merged object node is returned if (srcNode.isObject() && targetNode.isObject()) { return merge((ObjectNode) srcNode, (ObjectNode) targetNode); } // if both nodes are array node, merged array node is returned if (srcNode.isArray() && targetNode.isArray()) { return merge((ArrayNode) srcNode, (ArrayNode) targetNode); } // special case when src node is null if (srcNode.isNull()) { return targetNode; } return srcNode; } public static ObjectNode merge(ObjectNode srcNode, ObjectNode targetNode) { ObjectNode result = OBJECT_MAPPER.createObjectNode(); Iterator> srcItr = srcNode.fields(); while (srcItr.hasNext()) { Map.Entry entry = srcItr.next(); // check key in src json exists in target json or not at same level if (targetNode.has(entry.getKey())) { result.set(entry.getKey(), merge(entry.getValue(), targetNode.get(entry.getKey()))); } else { // if key in src json doesn't exist in target json, just copy the same in result result.set(entry.getKey(), entry.getValue()); } } // copy fields from target json into result which were missing in src json Iterator> targetItr = targetNode.fields(); while (targetItr.hasNext()) { Map.Entry entry = targetItr.next(); if (!result.has(entry.getKey())) { result.set(entry.getKey(), entry.getValue()); } } return result; } public static ArrayNode merge(ArrayNode srcNode, ArrayNode targetNode) { ArrayNode result = OBJECT_MAPPER.createArrayNode(); return result.addAll(srcNode).addAll(targetNode); } }