Confronta due oggetti JSON con Gson

1. Panoramica

JSON è una rappresentazione di stringa di dati. Potremmo voler confrontare questi dati nei nostri algoritmi o test. Sebbene sia possibile confrontare stringhe contenenti JSON, il confronto tra stringhe è sensibile alle differenze di rappresentazione , piuttosto che al contenuto.

Per superare questo problema e confrontare semanticamente i dati JSON, è necessario caricare i dati in una struttura in memoria che non sia influenzata da elementi come gli spazi o dall'ordine delle chiavi di un oggetto.

In questo breve tutorial, risolveremo questo problema utilizzando Gson, una libreria di serializzazione \ deserializzazione JSON che può eseguire un confronto approfondito tra oggetti JSON.

2. JSON semanticamente identico in stringhe diverse

Diamo uno sguardo più da vicino al problema che stiamo cercando di risolvere.

Supponiamo di avere due stringhe, che rappresentano gli stessi dati JSON, ma una di esse ha degli spazi extra alla fine:

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

Sebbene il contenuto degli oggetti JSON sia uguale, il confronto di quanto sopra come stringhe mostrerà una differenza:

assertNotEquals(string1, string2);

Lo stesso accadrebbe se l'ordine delle chiavi in ​​un oggetto fosse variato, anche se JSON di solito non è sensibile a questo:

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

Questo è il motivo per cui trarremmo vantaggio dall'utilizzo di una libreria di elaborazione JSON per confrontare i dati JSON.

3. Dipendenza da Maven

Per utilizzare Gson, aggiungiamo prima la dipendenza Gson Maven:

 com.google.code.gson gson 2.8.6 

4. Analisi di JSON in oggetti Gson

Prima di immergerci nel confronto degli oggetti, diamo un'occhiata a come Gson rappresenta i dati JSON in Java.

Quando lavoriamo con JSON in Java, dobbiamo prima convertire la stringa JSON in un oggetto Java. Gson fornisce JsonParser che analizza il JSON di origine in un albero 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 è una classe astratta, che rappresenta un elemento di JSON. Il metodo di analisi restituisce un'implementazione di JsonElement ; un JsonObject, JsonArray, JsonPrimitive o JsonNull:

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

Ciascuna di queste sottoclassi ( JsonObject, JsonArray e così via) sostituisce il metodo Object.equals , fornendo un confronto JSON approfondito efficace.

5. Casi d'uso di confronto Gson

5.1. Confronta due semplici oggetti JSON

Supponiamo di avere due stringhe, che rappresentano semplici oggetti JSON, in cui l'ordine delle chiavi è diverso:

Il primo oggetto ha fullName precedente a age :

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

Il secondo inverte l'ordine:

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

Possiamo semplicemente analizzarli e confrontarli:

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

In questo caso, JsonParser restituisce un JsonObject , la cui implementazione uguale non è sensibile all'ordine .

5.2. Confronta due array JSON

In un caso di array JSON, JsonParser restituirà un JsonArray.

Se abbiamo un array in un ordine:

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

Possiamo confrontarlo con un altro in un ordine diverso:

[20, 10, 30]

A differenza di JsonObject , il metodo equals di JsonArray è sensibile all'ordine , quindi questi array non sono uguali, il che è semanticamente corretto:

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

5.3. Confronta due oggetti JSON annidati

Come abbiamo visto in precedenza, JsonParser può analizzare la struttura ad albero di JSON. Ogni JsonObject e JsonArray contengono altri oggetti JsonElement , che possono essere di tipo JsonObject o JsonArray .

Quando usiamo uguale , confronta tutti i membri in modo ricorsivo, il che significa che anche gli oggetti annidati sono confrontabili:

Se è stringa1 :

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

E questo JSON è stringa2 :

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

Quindi possiamo ancora usare il metodo uguale per confrontarli:

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

6. Conclusione

In questo breve articolo, abbiamo esaminato le sfide del confronto di JSON come una stringa . Abbiamo visto come Gson ci permette di analizzare quelle stringhe in una struttura di oggetti che supporta il confronto.

Come sempre, il codice sorgente degli esempi sopra può essere trovato su GitHub.