Konvertieren Sie JSON mit Gson in eine Map

1. Einleitung

In diesem kurzen Tutorial erfahren Sie, wie Sie eine JSON-Zeichenfolge mit Gson von Google in eine Map konvertieren .

Wir werden drei verschiedene Ansätze sehen, um dies zu erreichen und ihre Vor- und Nachteile zu diskutieren - mit einigen praktischen Beispielen.

2. Map.class übergeben

Im Allgemeinen stellt Gson in seiner Gson- Klasse die folgende API zum Konvertieren einer JSON-Zeichenfolge in ein Objekt bereit :

public  T fromJson(String json, Class classOfT) throws JsonSyntaxException;

Aus der Signatur geht hervor, dass der zweite Parameter die Klasse des Objekts ist, in das der JSON analysieren soll. In unserem Fall sollte es Map.class sein :

String jsonString = "{'employee.name':'Bob','employee.salary':10000}"; Gson gson = new Gson(); Map map = gson.fromJson(jsonString, Map.class); Assert.assertEquals(2, map.size()); Assert.assertEquals(Double.class, map.get("employee.salary").getClass());

Bei diesem Ansatz wird der Werttyp für jede Eigenschaft am besten erraten.

Beispielsweise werden Zahlen in Double s, true und false in Boolean und Objekte in LinkedTreeMap s gezwungen .

Wenn jedoch doppelte Schlüssel vorhanden sind, schlägt der Zwang fehl und es wird eine JsonSyntaxException ausgelöst.

Und aufgrund der Typlöschung können wir dieses Zwangsverhalten auch nicht konfigurieren. Wenn wir also die Schlüssel- oder Werttypen angeben müssen, benötigen wir einen anderen Ansatz.

3. Verwenden von TypeToken

Um das Problem der Typlöschung für die generischen Typen zu lösen, verfügt Gson über eine überladene Version der API :

public  T fromJson(String json, Type typeOfT) throws JsonSyntaxException;

Wir können eine Map mit ihren Typparametern mit Gsons TypeToken erstellen . Die TypeToken- Klasse gibt eine Instanz von ParameterizedTypeImpl zurück , die den Typ des Schlüssels und den Wert auch zur Laufzeit beibehält :

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

Wenn wir unseren Map- Typ als Map konstruieren , wird der Parser weiterhin standardmäßig verwendet, wie wir im vorherigen Abschnitt gesehen haben.

Natürlich fällt dies immer noch auf Gson zurück, um primitive Typen zu erzwingen. Diese können jedoch auch angepasst werden.

4. Verwenden von Custom JsonDeserializer

Wenn wir eine detaillierte Kontrolle über die Konstruktion unseres Map- Objekts benötigen , können wir einen benutzerdefinierten Deserializer vom Typ JsonDeserializer implementieren.

Nehmen wir an, unser JSON enthält den Namen des Mitarbeiters als Schlüssel und dessen Einstellungsdatum als Wert. Nehmen wir weiter an, das Datumsformat ist JJJJ / MM / TT , was für Gson kein Standardformat ist .

Wir können Gson so konfigurieren, dass unsere Karte anders analysiert wird, indem wir einen JsonDeserializer implementieren :

public class StringDateMapDeserializer implements JsonDeserializer { private SimpleDateFormat format = new SimpleDateFormat("yyyy/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 value) { try { return format(value.getAsString()); } catch (ParseException ex) { throw new JsonParseException(ex); } } } 

Jetzt müssen wir es im GsonBuilder für unseren Zieltyp Map registrieren > und erstellen Sie ein benutzerdefiniertes Gson- Objekt.

Wenn wir die fromJson- API für dieses Gson- Objekt aufrufen , ruft der Parser den benutzerdefinierten Deserializer auf und gibt die gewünschte Map- Instanz zurück:

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

Diese Taktik ist auch nützlich, wenn unsere Karte heterogene Werte enthält und wir eine gute Vorstellung davon haben, wie viele verschiedene Arten von Werten vorhanden sein könnten.

Weitere Informationen zu einem benutzerdefinierten Deserializer in Gson finden Sie im Gson Deserialization Cookbook.

5. Schlussfolgerung

In diesem kurzen Artikel haben wir verschiedene Möglichkeiten zum Erstellen einer Karte aus einer JSON-formatierten Zeichenfolge kennengelernt. Außerdem haben wir die richtigen Anwendungsfälle für diese Variationen besprochen.

Der Quellcode für die Beispiele ist auf GitHub verfügbar.