Konvertiere JSON in eine Map mit Gson

Konvertieren Sie JSON in eine Karte mit Gson

1. Einführung

In this quick tutorial, we’ll learn how to convert a JSON string to a Map using Gson from Google.

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 AllgemeinenGson provides the following API in its Gson class to convert a JSON string to an object:

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 esMap.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 geschätzt.

Beispielsweise werden Zahlen inDoubles,true andfalse inBoolean und Objekte inLinkedTreeMaps gezwungen.

Wenn es jedoch doppelte Schlüssel gibt, schlägt der Zwang fehl und es werdenJsonSyntaxException. geworfen

Und aufgrund vontype erasure, 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 vonTypeToken

To overcome the problem of type-erasure for the generic types, Gson has an overloaded version of the API:

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

Wir können einMap mit seinen Typparametern unter Verwendung von GsonsTypeToken konstruieren. The TypeToken class returns an instance of ParameterizedTypeImpl that preserves the type of the key and value even at runtime:

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 nun unserenMap-Typ alsMap<String, Object> 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 zwingen. Diese können jedoch auch angepasst werden.

4. Verwenden von benutzerdefiniertenJsonDeserializer

Wenn wir eine genauere Kontrolle über die Konstruktion unseresMap-Objekts benötigen, können wir einen benutzerdefinierten Deserializer vom TypJsonDeserializer<Map>. implementieren

Nehmen wir an, unser JSON enthält den Namen des Mitarbeiters als Schlüssel und dessen Einstellungsdatum als Wert. Nehmen wir weiter an, dass das Datumsformatyyyy/MM/dd ist, was kein Standardformat fürGson ist.

Wir können Gson so konfigurieren, dass unsere Karte anders analysiert wird, indem wirJsonDeserializer: 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 inGsonBuilder gegen unseren ZieltypMap<String, Date> registrieren und ein benutzerdefiniertesGson-Objekt erstellen.

Wenn wir diefromJson-API für diesesGson-Objekt aufrufen, ruft der Parser den benutzerdefinierten Deserializer auf und gibt die gewünschteMap-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 enthalten kann und wir eine gute Vorstellung davon haben, wie viele verschiedene Arten von Werten vorhanden sein können.

Um mehr über einen benutzerdefinierten Deserializer inGson zu erfahren, können Sie dieGson Deserialization Cookbook durchgehen.

5. Fazit

In diesem kurzen Artikel haben wir verschiedene Möglichkeiten kennengelernt, eine Map aus einer JSON-formatierten Zeichenfolge zu erstellen. Wir haben auch die richtigen Anwendungsfälle für diese Variationen besprochen.

Der Quellcode für die Beispiele istover on GitHub verfügbar.