Contents

GSON中JSON对象比较

1. 概述

JSON 是数据的字符串表示形式。我们可能希望在我们的算法或测试中比较这些数据。尽管可以比较包含 JSON 的字符串,但字符串比较对表示的差异很敏感,而不是内容。

为了克服这个问题并在语义上比较 JSON 数据,我们需要将数据加载到内存中不受空格或对象键顺序影响的结构中。 在这个简短的教程中,我们将使用Gson 来解决这个问题,这是一个 JSON 序列化\反序列化库,可以在 JSON 对象之间进行深度比较。

2. 不同字符串中语义相同的 JSON

让我们仔细看看我们试图解决的问题。

假设我们有两个字符串,代表相同的 JSON 数据,但其中一个在其末尾有一些额外的空格:

String string1 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27    }";
String string2 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27}";

尽管 JSON 对象的内容是相等的,但将上面的内容作为字符串进行比较会显示出差异:

assertNotEquals(string1, string2);

如果对象中键的顺序不同,也会发生同样的情况,即使 JSON 通常对此不敏感:

String string1 = "{\"fullName\": \"Emily Jenkins\", \"age\": 27}";
String string2 = "{\"age\": 27, \"fullName\": \"Emily Jenkins\"}";
assertNotEquals(string1, string2);

这就是为什么我们会受益于使用 JSON 处理库来比较 JSON 数据的原因。

3. Maven依赖

要使用 Gson,我们首先添加Gson Maven 依赖 项:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

4. 将 JSON 解析为 Gson 对象

在深入比较对象之前,让我们看一下 Gson 如何在 Java 中表示 JSON 数据。

在 Java 中使用 JSON 时,我们首先需要将 JSON 字符串转换为 Java 对象。Gson 提供JsonParser 将源 JSON 解析为*JsonElement *树:

JsonParser parser = new JsonParser();
String objectString = "{\"customer\": {\"fullName\": \"Emily Jenkins\", \"age\": 27 }}";
String arrayString = "[10, 20, 30]";
JsonElement json1 = parser.parse(objectString);
JsonElement json2 = parser.parse(arrayString);

JsonElement是一个抽象类,代表 JSON 的一个元素。parse方法返回JsonElement的实现;JsonObject JsonArrayJsonPrimitiveJsonNull

assertTrue(json1.isJsonObject());
assertTrue(json2.isJsonArray());

这些子类中的每一个(JsonObjectJsonArray等)都会覆盖Object.equals方法,从而提供有效的深度 JSON 比较。

5. Gson 比较用例

5.1. 比较两个简单的 JSON 对象

假设我们有两个字符串,代表简单的 JSON 对象,其中键的顺序不同:

第一个对象的fullName早于age

{
    "customer": {
        "id": 44521,
        "fullName": "Emily Jenkins",
        "age": 27
    }
}

第二个颠倒顺序:

{
    "customer": {
        "id": 44521,
        "age": 27,
        "fullName": "Emily Jenkins"
    }
}

我们可以简单地解析和比较它们:

assertEquals(parser.parse(string1), parser.parse(string2));

在这种情况下,JsonParser返回一个JsonObjectequals实现不是order-sensitive

5.2. 比较两个 JSON 数组

在 JSON 数组的情况下,JsonParser将返回一个JsonArray

如果我们有一个数组按一个顺序:

[10, 20, 30]
assertTrue(parser.parse(string1).isJsonArray());

我们可以以不同的顺序将其与另一个进行比较:

[20, 10, 30]

JsonObject不同,JsonArrayequals方法是 order-sensitive,因此这些数组不相等,这在语义上是正确的:

assertNotEquals(parser.parse(string1), parser.parse(string2));

5.3. 比较两个嵌套的 JSON 对象

正如我们之前看到的,JsonParser可以解析 JSON 的树状结构。每个JsonObjectJsonArray 都包含其他JsonElement对象,它们本身可以是JsonObjectJsonArray类型。

当我们使用equals时,它递归地比较所有成员,这意味着嵌套对象也是可比较的:

如果这是string1

{
  "customer": {
    "id": "44521",
    "fullName": "Emily Jenkins",
    "age": 27,
    "consumption_info": {
      "fav_product": "Coke",
      "last_buy": "2012-04-23"
    }
  }
}

这个 JSON 是string2

{
  "customer": {
    "fullName": "Emily Jenkins",
    "id": "44521",
    "age": 27,
    "consumption_info": {
      "last_buy": "2012-04-23",
      "fav_product": "Coke"
   }
  }
}

然后我们仍然可以使用equals方法来比较它们:

assertEquals(parser.parse(string1), parser.parse(string2));