Maps mittels GSON deserialisieren

GSON ist eine von Google entwickelte Java-Bibliothek, welche ursprünglich für den internen Gebrauch bei Google gedacht war. Mit dieser ist, neben vielen anderen Dingen, unter anderem die Serialisierung von Java-Objekten in JSON möglich. Gegeben sei für ein kleines Beispiel die Klasse FooObject:

public class FooObject {

    private int id;
    private String key;
    private String value;

    public FooObject(int id, String key, String value) {
        this.id = id;
        this.key = key;
        this.value = value;
    }

    public int getId() {
        return id;
    }

    public String getKey() {
        return key;
    }

    public String getValue() {
        return value;
    }
}

Die Klasse besteht aus drei internen Variablen, welche eine Id, einen Key und einen Value halten. Daneben existieren ein Konstruktor und drei Getter-Methoden für die Rückgabe der internen Variablen. Mithilfe von GSON kann eine Instanz der Klasse einfach zu JSON serialisiert werden:

Gson gson = new Gson();
FooObject fooObject = new FooObject(1, "keyA", "valueA");
String jsonFooObject = gson.toJson(fooObject);

Heraus kommt bei dieser Serialisierung folgendes JSON-Objekt:

{
   "id":1,
   "key":"keyA",
   "value":"valueA"
}

Auch die Deserialisierung des Objektes mittels GSON ist kein Problem:

fooObject = gson.fromJson(jsonFooObject, FooObject.class);

Interessanter und komplizierter wird es, wenn Maps mittels GSON serialisiert werden sollen:

Map values = new HashMap<>();
values.put("A", new FooObject(1, "keyA", "valueA"));
values.put("B", new FooObject(2, "keyB", "valueB"));
values.put("C", new FooObject(3, "keyC", "valueC"));

Die Serialisierung gestaltet sich noch einfach:

String json = gson.toJson(values);

Bei der Deserialisierung mittels:

Map map = gson.fromJson(json, Map.class);

erhält der Nutzer allerdings eine LinkedTreeMap. Auf die Werte der Map kann durchaus zugegriffen werden:

String value = map.get("A").get("key");

Allerdings schlägt die Umwandlung in ein Objekt vom Typ FooObject fehl:

FooObject fooObjectB = map.get("A");

Stattdessen erhält der Nutzer eine ClassCastException:

Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to org.example.console.FooObject

Damit der Cast gelingt muss bei der Deserialisierung der Map anders gearbeitet werden:

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;

...

Type type = new TypeToken>(){}.getType();
Map map = gson.fromJson(json, type);

Damit kann die Map mit dem FooObject normal genutzt werden. Mithilfe des TypeTokens kann ein generischer Typ repräsentiert und somit für die Deserialisierung mittels GSON eingesetzt werden.