Jackson 比较两个忽略缺失字段的任意 JsonNodes

问题描述 投票:0回答:2

我有一个程序,可以比较两个响应主体,但我不知道主体是什么样子,所以我没有将它们反序列化为 Java 对象,而是将它们保留为 JsonNode 对象。假设我有以下两个 JsonNode 对象:

{
  "name": "Bob",
  "Age": 30,
  "id": 1,
  "status" : {
    "active": "true",
    "address": "123 Main St"
  }
}

{
  "name": "Bob",
  "Age": 30,
  "status" : {
    "active": "true"
  }
}

第二个 JsonNode 对象缺少

id
status.address
字段。但是,对于两个 JsonNode 对象存在的字段,它们是相等的。在比较它们时,我想忽略比较缺失的字段,而只比较两个 JsonNode 对象中存在的字段。同样,我无法将它们反序列化为对象并通过 Jackson 注释进行比较。所以我的限制是:

  1. 我不知道响应体在运行时会是什么样子,但是第一个 JsonNode 的所有字段都会出现在第二个 JsonNode 中,但是第二个 JsonNode 可能具有第一个 JsonNode 中不存在的字段。
  2. 比较两个 JsonNode 对象中出现的字段

杰克逊有什么办法可以实现这一点吗?如果可以的话,有人可以指出它的文档吗?我认为我必须编写自己的比较器,但是任何现有的文献都会有所帮助。

java json jackson jackson-databind
2个回答
0
投票

您需要编写自定义比较。一种选择是将

JsonNode.equals(Comparator, JsonNode)
与自定义比较器一起使用。但由于您不关心排序,因此最好只进行相等性检查。下面的示例使用递归来深度优先检查节点。根据实际用例,您可能需要切换到广度优先算法。

public class CustomNodeComparator {

  public static boolean customEquals(JsonNode node1, JsonNode node2) {
    JsonNodeType node1Type = node1.getNodeType();
    if (!node1Type.equals(node2.getNodeType())) {
      //array and object are not equal
      return false;
    }
    Iterator<String> names = node1.fieldNames();
    while (names.hasNext()) {
      String name = names.next();
      JsonNode o2Node = node2.get(name);
      if (o2Node == null) {
        //assume equal, continue with other nodes
        continue;
      }
      JsonNode o1Node = node1.get(name);
      if (!o1Node.isValueNode()) {
        return customEquals(o1Node, o2Node);
      }
      //compares everything as text
      //depending on requirements you may need to compare taking value type into consideration
      boolean isEqual = o1Node.asText().equals(o2Node.asText());
      if (!isEqual) {
        //end fast, no need to compare the rest
        return false;
      }
    }
    return true;
  }
}

请注意,该示例没有考虑比较两个数组的可能性。


0
投票

您可以尝试使用库 Josson & Jossons 按运算符比较两个 JSON 数据集:

左减右

<-<

右减左
>->

它也可以处理数组比较。

https://github.com/octomix/josson

Jossons jossons = new Jossons();
jossons.putDataset("json1", Josson.fromJsonString(
    "{" +
    "  \"name\": \"Bob\"," +
    "  \"Age\": 30," +
    "  \"id\": 1," +
    "  \"status\" : {" +
    "    \"active\": \"true\"," +
    "    \"array1\": [1,2,3]," +
    "    \"array2\": [4,5]," +
    "    \"address\": \"123 Main St\"" +
    "  }" +
    "}"));
jossons.putDataset("json2", Josson.fromJsonString(
    "{" +
    "  \"name\": \"Bob\"," +
    "  \"Age\": 30," +
    "  \"status\" : {" +
    "    \"array1\": [3,2,1]," +
    "    \"array2\": [6,5]," +
    "    \"active\": \"true\"" +
    "  }" +
    "}"));
System.out.println(jossons.evaluateQuery("json1 <-< json2").toPrettyString());

输出

{
  "id" : 1,
  "status" : {
    "array2" : [ 4 ],
    "address" : "123 Main St"
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.