Comparar dos objetos JSON con Gson

1. Información general

JSON es una representación de cadena de datos. Es posible que deseemos comparar estos datos en nuestros algoritmos o pruebas. Y aunque es posible comparar cadenas que contienen JSON, la comparación de cadenas es sensible a las diferencias en la representación , más que al contenido.

Para superar esto y comparar los datos JSON semánticamente, necesitamos cargar los datos en una estructura en la memoria que no se vea afectada por cosas como espacios en blanco o por el orden de las claves de un objeto.

En este breve tutorial, resolveremos esto usando Gson, una biblioteca de serialización / deserialización JSON que puede hacer una comparación profunda entre objetos JSON.

2. JSON semánticamente idéntico en diferentes cadenas

Echemos un vistazo más de cerca al problema que estamos tratando de resolver.

Supongamos que tenemos dos cadenas, que representan los mismos datos JSON, pero una de ellas tiene algunos espacios adicionales al final:

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

Aunque el contenido de los objetos JSON es igual, comparar lo anterior como cadenas mostrará una diferencia:

assertNotEquals(string1, string2);

Lo mismo sucedería si se variara el orden de las claves en un objeto, aunque JSON generalmente no es sensible a esto:

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

Es por eso que nos beneficiaríamos de usar una biblioteca de procesamiento JSON para comparar datos JSON.

3. Dependencia de Maven

Para usar Gson, primero agreguemos la dependencia de Gson Maven:

 com.google.code.gson gson 2.8.6 

4. Analizar JSON en objetos Gson

Antes de sumergirnos en la comparación de objetos, echemos un vistazo a cómo Gson representa los datos JSON en Java.

Cuando trabajamos con JSON en Java, primero debemos convertir la cadena JSON en un objeto Java. Gson proporciona JsonParser que analiza el código fuente JSON en un árbol 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 es una clase abstracta que representa un elemento de JSON. El método de análisis devuelve una implementación de JsonElement ; ya sea un JsonObject, JsonArray, JsonPrimitive o JsonNull:

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

Cada una de esas subclases ( JsonObject, JsonArray, etc.) anula el método Object.equals , proporcionando una comparación JSON profunda y efectiva.

5. Casos de uso de comparación de Gson

5.1. Comparar dos objetos JSON simples

Supongamos que tenemos dos cadenas, que representan objetos JSON simples, donde el orden de las claves es diferente:

El primer objeto tiene fullName antes de age :

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

El segundo invierte el orden:

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

Simplemente podemos analizarlos y compararlos:

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

En este caso, JsonParser devuelve un JsonObject , cuya implementación igual no es sensible al orden .

5.2. Comparar dos matrices JSON

En el caso de matrices JSON, JsonParser devolverá un JsonArray.

Si tenemos una matriz en un orden:

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

Podemos compararlo con otro en un orden diferente:

[20, 10, 30]

A diferencia de JsonObject , el método equals de JsonArray es sensible al orden , por lo que estas matrices no son iguales, lo cual es semánticamente correcto:

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

5.3. Comparar dos objetos JSON anidados

Como vimos anteriormente, JsonParser puede analizar la estructura en forma de árbol de JSON. Cada JsonObject y JsonArray contienen otros objetos JsonElement , que pueden ser de tipo JsonObject o JsonArray .

Cuando usamos iguales , compara todos los miembros de forma recursiva, lo que significa que los objetos anidados también son comparables:

Si esto es string1 :

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

Y este JSON es string2 :

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

Entonces todavía podemos usar el método equals para compararlos:

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

6. Conclusión

En este breve artículo, analizamos los desafíos de comparar JSON como una cadena . Hemos visto cómo Gson nos permite analizar esas cadenas en una estructura de objeto que admite la comparación.

Como siempre, el código fuente de los ejemplos anteriores se puede encontrar en GitHub.