使用Jackson合并两个JSON文档

Dan*_*ish 40 java json jackson

是否可以将两个JSON文档与Jackson JSON库合并?我基本上使用Jackson mapper和简单的Java Maps.

我试图在谷歌和杰克逊的文档中搜索,但找不到任何东西.

Arn*_*rne 54

受到StaxMans答案的启发,我实现了这种合并方法.

public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) {

    Iterator<String> fieldNames = updateNode.fieldNames();
    while (fieldNames.hasNext()) {

        String fieldName = fieldNames.next();
        JsonNode jsonNode = mainNode.get(fieldName);
        // if field exists and is an embedded object
        if (jsonNode != null && jsonNode.isObject()) {
            merge(jsonNode, updateNode.get(fieldName));
        }
        else {
            if (mainNode instanceof ObjectNode) {
                // Overwrite field
                JsonNode value = updateNode.get(fieldName);
                ((ObjectNode) mainNode).put(fieldName, value);
            }
        }

    }

    return mainNode;
}
Run Code Online (Sandbox Code Playgroud)

希望这有助于某人.

  • 优秀,Arne,这正是我所需要的,你节省了我几个小时的调查,谢谢.为了使这一点多于"谢谢"评论,从Jackson 2.4开始,put()`已被弃用,应该用`replace()`代替.此外,对于JDK8用户,代码可以更简洁,直接在迭代器上调用`forEachRemaining()`并传入更短的lambda表达式. (3认同)

Sta*_*Man 45

一种方法是这样使用ObjectReader:

MyBean defaults = objectMapper.readValue(defaultJson, MyBean.class);
ObjectReader updater = objectMapper.readerForUpdating(defaults);
MyBean merged = updater.readValue(overridesJson);
Run Code Online (Sandbox Code Playgroud)

它将结合两个来源的数据.这只是一个浅拷贝,即不对包含的对象进行递归合并.

否则,您可能只需要将JSON读取为树(JsonNode),循环内容并手动合并.这通常是有道理的,因为合并的规则并不是微不足道的,每个人都有自己的合并应该如何运作的想法.

编辑:(2017年4月3日)

根据@Fernando Correia的评论,实际上在即将推出的Jackson 2.9(将于2017年4月或5月发布)中添加了一项新功能,最终可以实现深度合并.

  • 它是为(即将推出)版本2.9实现的:https://github.com/FasterXML/jackson-databind/issues/1399 (3认同)

Jay*_*ani 12

灵感来自Arn的回答.编辑它以添加节点可能包含节点数组的情况.

public static JsonNode merge(JsonNode mainNode, JsonNode updateNode) {

    Iterator<String> fieldNames = updateNode.fieldNames();

    while (fieldNames.hasNext()) {
        String updatedFieldName = fieldNames.next();
        JsonNode valueToBeUpdated = mainNode.get(updatedFieldName);
        JsonNode updatedValue = updateNode.get(updatedFieldName);

        // If the node is an @ArrayNode
        if (valueToBeUpdated != null && valueToBeUpdated.isArray() && 
            updatedValue.isArray()) {
            // running a loop for all elements of the updated ArrayNode
            for (int i = 0; i < updatedValue.size(); i++) {
                JsonNode updatedChildNode = updatedValue.get(i);
                // Create a new Node in the node that should be updated, if there was no corresponding node in it
                // Use-case - where the updateNode will have a new element in its Array
                if (valueToBeUpdated.size() <= i) {
                    ((ArrayNode) valueToBeUpdated).add(updatedChildNode);
                }
                // getting reference for the node to be updated
                JsonNode childNodeToBeUpdated = valueToBeUpdated.get(i);
                merge(childNodeToBeUpdated, updatedChildNode);
            }
        // if the Node is an @ObjectNode
        } else if (valueToBeUpdated != null && valueToBeUpdated.isObject()) {
            merge(valueToBeUpdated, updatedValue);
        } else {
            if (mainNode instanceof ObjectNode) {
                ((ObjectNode) mainNode).replace(updatedFieldName, updatedValue);
            }
        }
    }
    return mainNode;
}
Run Code Online (Sandbox Code Playgroud)


rog*_*one 6

下面是 Scala 中的一个实现。源节点和目标节点大部分是可交换的,除非源节点和目标节点中都存在分支。

  def mergeYamlObjects(source: ObjectNode, target: ObjectNode, overwrite: Boolean = true): ObjectNode = {
    if (target == null)
      source
    else if (source == null)
      target
    else {
      val result = source.deepCopy
      val fieldlist = source.fieldNames.asScala.toList ++ target.fieldNames.asScala.toList
      for (item <- fieldlist) {
        if (!(source has item)) {
          result put(item, target get item)
        } else {
          if ((source get item).isValueNode) {
            if (target has item)
              if (overwrite)
                result.put(item, target get item)
          } else {
            result.put(item, mergeYamlObjects(source.get(item).asInstanceOf[ObjectNode],
              target.get(item).asInstanceOf[ObjectNode], overwrite = overwrite))
          }
        }
      }
      result
    }
  }
Run Code Online (Sandbox Code Playgroud)


小智 6

如果有人只是想将两个或多个 JsonNode 对象添加到一个 JsonNode 中,这可以是一种方法:

ArrayNode arrayNode = objectMapper.createArrayNode();
arrayNode.add(firstJsonNode);
arrayNode.add(secondJsonNode);
arrayNode.add(thirdJsonNode);

JsonNode root = JsonNodeFactory.instance.objectNode();
((ObjectNode) root).put("", arrayNode);
System.out.println("merged array node #: " + root);
Run Code Online (Sandbox Code Playgroud)