ti-enxame.com

Gson: Existe uma maneira mais fácil de serializar um mapa

Este link do projeto Gson parece indicar que eu teria que fazer algo como o seguinte para serializar um mapa digitado para JSON:

    public static class NumberTypeAdapter 
      implements JsonSerializer<Number>, JsonDeserializer<Number>,
InstanceCreator<Number> {

    public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext
context) {
      return new JsonPrimitive(src);
    }

    public Number deserialize(JsonElement json, Type typeOfT,
JsonDeserializationContext context)
        throws JsonParseException {
      JsonPrimitive jsonPrimitive = json.getAsJsonPrimitive();
      if (jsonPrimitive.isNumber()) {
        return jsonPrimitive.getAsNumber();
      } else {
        throw new IllegalStateException("Expected a number field, but was " + json);
      }
    }

    public Number createInstance(Type type) {
      return 1L;
    }
  }

  public static void main(String[] args) {
    Map<String, Number> map = new HashMap<String, Number>();    
    map.put("int", 123);
    map.put("long", 1234567890123456789L);
    map.put("double", 1234.5678D);
    map.put("float", 1.2345F);
    Type mapType = new TypeToken<Map<String, Number>>() {}.getType();

    Gson gson = new GsonBuilder().registerTypeAdapter(Number.class, new
NumberTypeAdapter()).create();
    String json = gson.toJson(map, mapType);
    System.out.println(json);

    Map<String, Number> deserializedMap = gson.fromJson(json, mapType);
    System.out.println(deserializedMap);
  }

Legal e isso funciona, mas parece muita sobrecarga ( toda uma classe de adaptadores de tipo? ) . Eu usei outras bibliotecas JSON como JSONLib e elas permitem criar um mapa da seguinte maneira:

JSONObject json = new JSONObject();
for(Entry<String,Integer> entry : map.entrySet()){
     json.put(entry.getKey(), entry.getValue());
}

Ou se eu tiver uma classe personalizada, algo como o seguinte:

JSONObject json = new JSONObject();
for(Entry<String,MyClass> entry : map.entrySet()){
 JSONObject myClassJson =  JSONObject.fromObject(entry.getValue());
     json.put(entry.getKey(), myClassJson);
}

O processo é mais manual, mas requer muito menos código e não possui a sobrecarga de haivng para criar um Adaptador de Tipo personalizado para Number ou na maioria dos casos para o meu própria classe personalizada .

Essa é a única maneira de serializar um mapa com o Gson, ou alguém encontrou uma maneira de superar o que o Gson recomenda no link acima.

55
stevebot

Somente a parte TypeToken é necessária (quando houver Genética envolvida).

Map<String, String> myMap = new HashMap<String, String>();
myMap.put("one", "hello");
myMap.put("two", "world");

Gson gson = new GsonBuilder().create();
String json = gson.toJson(myMap);

System.out.println(json);

Type typeOfHashMap = new TypeToken<Map<String, String>>() { }.getType();
Map<String, String> newMap = gson.fromJson(json, typeOfHashMap); // This type must match TypeToken
System.out.println(newMap.get("one"));
System.out.println(newMap.get("two"));

Saída:

{"two":"world","one":"hello"}
hello
world
114
arturo

Default

A implementação padrão do Gson da serialização de mapas usa toString() na chave:

Gson gson = new GsonBuilder()
        .setPrettyPrinting().create();
Map<Point, String> original = new HashMap<>();
original.put(new Point(1, 2), "a");
original.put(new Point(3, 4), "b");
System.out.println(gson.toJson(original));

Darei:

{
  "Java.awt.Point[x\u003d1,y\u003d2]": "a",
  "Java.awt.Point[x\u003d3,y\u003d4]": "b"
}

Usando enableComplexMapKeySerialization

Se você deseja que a Chave do Mapa seja serializada de acordo com as regras padrão do Gson, use enableComplexMapKeySerialization . Isso retornará uma matriz de matrizes de pares de valores-chave:

Gson gson = new GsonBuilder().enableComplexMapKeySerialization()
        .setPrettyPrinting().create();
Map<Point, String> original = new HashMap<>();
original.put(new Point(1, 2), "a");
original.put(new Point(3, 4), "b");
System.out.println(gson.toJson(original));

Retornará:

[
  [
    {
      "x": 1,
      "y": 2
    },
    "a"
  ],
  [
    {
      "x": 3,
      "y": 4
    },
    "b"
  ]
]

Mais detalhes podem ser encontrados aqui .

84
matt burns

Tenho certeza de que o GSON serializa/desserializa o Google Maps e vários mapas aninhados (por exemplo, Map<String, Map<String, Object>>) por padrão. O exemplo fornecido, acredito, nada mais é do que apenas um ponto de partida, se você precisar fazer algo mais complexo.

Confira a classe MapTypeAdapterFactory na fonte GSON: http://code.google.com/p/google-gson/source/browse/trunk/gson/src/main/Java/com/google/gson/ internal/bind/MapTypeAdapterFactory.Java

Desde que os tipos de chaves e valores possam ser serializados em cadeias JSON (e você possa criar seus próprios serializadores/desserializadores para esses objetos personalizados), você não deverá ter nenhum problema.

4
Ankit Aggarwal

No Gson 2.7.2, é tão fácil quanto

Gson gson = new Gson();
String serialized = gson.toJson(map);
3
isapir