Перейти к основному содержимому

Сравните два объекта JSON с Gson

· 4 мин. чтения

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 представляет данные JSON в Java.

При работе с JSON в Java нам сначала нужно преобразовать строку 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, JsonArray, JsonPrimitive или JsonNull:

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

Каждый из этих подклассов ( JsonObject, JsonArray и т. д .) переопределяет метод 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 возвращает JsonObject , реализация equals которого не зависит от порядка .

5.2. Сравните два массива JSON

В случае массивов JSON JsonParser вернет JsonArray.

Если у нас есть один массив в одном порядке:

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

Мы можем сравнить его с другим в другом порядке:

[20, 10, 30]

В отличие от JsonObject , метод equals JsonArray чувствителен к порядку , `` поэтому эти массивы не равны, что семантически правильно:

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

5.3. Сравните два вложенных объекта JSON

Как мы видели ранее, JsonParser может анализировать древовидную структуру JSON. Каждый JsonObject и JsonArray содержат другие объекты JsonElement , которые сами могут иметь тип JsonObject или JsonArray .

Когда мы используем equals , он рекурсивно сравнивает все элементы, что означает, что вложенные объекты также сопоставимы:

Если это строка1 :

{
"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));

6. Заключение

В этой короткой статье мы рассмотрели проблемы сравнения JSON как String . Мы видели, как Gson позволяет нам анализировать эти строки в объектной структуре, поддерживающей сравнение.

Как всегда, исходный код приведенных выше примеров можно найти на GitHub .