Converteer JSON naar een kaart met Gson

1. Inleiding

In deze korte tutorial leren we hoe je een JSON-string converteert naar een Kaart gebruik makend van Gson van Google.

We zullen drie verschillende benaderingen zien om dat te bereiken en hun voor- en nadelen bespreken - met enkele praktische voorbeelden.

2. Passeren Kaart. Klasse

Over het algemeen, Gson biedt de volgende API in zijn Gson class om een ​​JSON-string naar een object te converteren:

openbare T fromJson (String json, Class classOfT) gooit JsonSyntaxException;

Uit de handtekening is het heel duidelijk dat de tweede parameter de klasse is van het object waarin we de JSON willen parseren. In ons geval zou het moeten zijn Kaart. Klasse:

String jsonString = "{'medewerker.name': 'Bob', 'medewerker.salaris': 10000}"; Gson gson = nieuwe Gson (); Map map = gson.fromJson (jsonString, Map.class); Assert.assertEquals (2, map.size ()); Assert.assertEquals (Double.class, map.get ("werknemer.salaris"). GetClass ());

Deze benadering maakt de beste schatting met betrekking tot het waardetype voor elke eigenschap.

Getallen worden bijvoorbeeld gedwongen tot Dubbeles, waar en false in Boolean, en objecten in LinkedTreeMaps.

Als er echter dubbele sleutels zijn, zal dwang mislukken en wordt een JsonSyntaxException.

En vanwege type wissen, we zullen dit dwanggedrag ook niet kunnen configureren. Dus als we de sleutel- of waardetypes moeten specificeren, hebben we een andere benadering nodig.

3. Met behulp van TypeToken

Om het probleem van het wissen van lettertypen voor de generieke typen op te lossen, Gson heeft een overbelaste versie van de API:

openbare T fromJson (String json, Type typeOfT) gooit JsonSyntaxException;

We kunnen een Kaart met zijn typeparameters met behulp van Gson's TypeToken. De TypeToken class retourneert een instantie van ParameterizedTypeImpl dat behoudt het type van de sleutel en waarde, zelfs tijdens runtime:

String jsonString = "{'Bob': {'naam': 'Bob Willis'}," + "'Jenny': {'naam': 'Jenny McCarthy'}," + "'Steve': {'naam': 'Steven Waugh'}} "; Gson gson = nieuwe Gson (); Typ empMapType = nieuw TypeToken() {} .getType (); Map nameEmployeeMap = gson.fromJson (jsonString, empMapType); Assert.assertEquals (3, nameEmployeeMap.size ()); Assert.assertEquals (Employee.class, nameEmployeeMap.get ("Bob"). GetClass ()); 

Als we nu onze Kaart typ als Kaart, dan zal de parser nog steeds standaard zijn, zoals we in de vorige sectie hebben gezien.

Dit valt natuurlijk nog steeds terug op Gson voor het dwingen van primitieve typen. Die kunnen echter ook worden aangepast.

4. Aangepast gebruiken JsonDeserializer

Wanneer we een fijnmazige controle nodig hebben over de constructie van onze Kaart object, kunnen we een aangepaste deserializer van het type implementeren JsonDeserializer.

Laten we, om een ​​voorbeeld te zien, aannemen dat onze JSON de naam van de werknemer als sleutel bevat en hun aanwervingsdatum als waarde. Laten we verder aannemen dat het formaat van de datum is jjjj / MM / dd, wat geen standaardformaat is voor Gson.

We kunnen Gson configureren om onze kaart anders te parseren door een JsonDeserializer:

public class StringDateMapDeserializer implementeert JsonDeserializer {privé SimpleDateFormat-indeling = nieuwe SimpleDateFormat ("jjjj / MM / dd"); @Override public Map deserialize (JsonElement elem, Type type, JsonDeserializationContext jsonDeserializationContext) {return elem.getAsJsonObject () .entrySet () .stream () .filter (e -> e.getValue (). IsJsonPrimitive ()). Filter (e -> e.getValue (). getAsJsonPrimitive (). isString ()) .collect (Collectors.toMap (Map.Entry :: getKey, e -> formatDate (e.getValue ()))); } private Date formatDate (Object waarde) {probeer {return format (value.getAsString ()); } catch (ParseException ex) {throw nieuwe JsonParseException (ex); }}} 

Nu moeten we het registreren in het GsonBuilder tegen ons doeltype Kaart> en bouw een op maat gemaakt Gson voorwerp.

Als we de van Json API op dit Gson object, roept de parser de aangepaste deserializer aan en retourneert het gewenste Kaart voorbeeld:

String jsonString = "{'Bob': '2017-06-01', 'Jennie': '2015-01-03'}"; Typ type = nieuw TypeToken() {}. getType (); Gson gson = nieuwe GsonBuilder () .registerTypeAdapter (type, nieuwe StringDateMapDeserializer ()) .create (); Kaart empJoiningDateMap = gson.fromJson (jsonString, type); Assert.assertEquals (2, empJoiningDateMap.size ()); Assert.assertEquals (Date.class, empJoiningDateMap.get ("Bob"). GetClass ()); 

Deze tactiek is ook handig wanneer onze kaart heterogene waarden kan bevatten en we een redelijk idee hebben van hoeveel verschillende soorten waarden er zouden kunnen zijn.

Voor meer informatie over een aangepaste deserializer in Gson, neem dan gerust het Gson Deserialization Cookbook door.

5. Conclusie

In dit korte artikel hebben we verschillende manieren geleerd om een ​​kaart te maken op basis van een JSON-opgemaakte tekenreeks. En we bespraken ook de juiste use-cases voor deze variaties.

De broncode voor de voorbeelden is beschikbaar op GitHub.