2011-03-22 25 views
8

Tengo un mapa que contiene una mezcla de tipos como en este ejemplo sencillodeserializar Mapa <Object, Object> con GSON

final Map<String, Object> map = new LinkedHashMap<String, Object>(); 
map.put("a", 1); 
map.put("b", "a"); 
map.put("c", 2); 
final Gson gson = new Gson(); 
final String string = gson.toJson(map); 
final Type type = new TypeToken<LinkedHashMap<String, Object>>(){}.getType(); 
final Map<Object, Object> map2 = gson.fromJson(string, type); 
for (final Entry<Object, Object> entry : map2.entrySet()) { 
    System.out.println(entry.getKey() + " : " + entry.getValue()); 
} 

Lo que vuelva son claras Object s, no hay Integer s, no hay String s. La salida se ve como

a : [email protected] 
b : [email protected] 
c : [email protected] 

¿Puedo arreglarlo de alguna manera? Esperaría que casos tan simples se manejen correctamente de manera predeterminada.

Sé que la información sobre el tipo no siempre se puede conservar, y posiblemente 1 y "1" significa exactamente lo mismo en JSON. Sin embargo, devolver objetos simples sin contenido simplemente no tiene sentido para mí.

Actualización: La versión serializada (es decir, el string arriba) se ve bien:

{"a":1,"b":"a","c":2} 
+0

¿Podría ver lo que parece la 'cadena de cadena final'? Estoy seguro de que ayudaría a comprender el problema. –

+0

Acabo de encontrar esto también ... Es por eso que uso mi JSONer ... podría ser un poco más lento, pero es mucho más genérico que Gson: http://nu-art-infrastructure.blogspot.co .il/2013/03/jsoner.html – TacB0sS

+0

@ TacB0sS: en su lugar, he seguido el consejo de "estructura de datos estática y clara". Sin embargo, hacer que Gson maneje esto debería ser bastante trivial. ¿Te importa archivar un problema? – maaartinus

Respuesta

6

Gson no es tan inteligente. Más bien, proporcione una estructura de datos clara y estática en el sabor de una clase Javabean para que Gson comprenda a qué tipo se supone que se deserializan las propiedades separadas.

E.g.

public class Data { 
    private Integer a; 
    private String b; 
    private Integer c; 
    // ... 
} 

en combinación con

Data data1 = new Data(1, "a", 2); 
String json = gson.toJson(data1); 
Data data2 = gson.fromJson(json, Data.class); 

actualización: según los comentarios, el conjunto de claves no parece ser fijo (aunque usted parece ser capaz de convertir manualmente más tarde sin saber la estructura de antemano). Puede crear un custom deserializer. Aquí hay un ejemplo rápido y sucio.

public class ObjectDeserializer implements JsonDeserializer<Object> { 

    @Override 
    public Object deserialize(JsonElement element, Type type, JsonDeserializationContext context) throws JsonParseException { 
     String value = element.getAsString(); 
     try { 
      return Long.valueOf(value); 
     } catch (NumberFormatException e) { 
      return value; 
     } 
    } 

} 

que se utiliza de la siguiente manera:

final Gson gson = new GsonBuilder().registerTypeAdapter(Object.class, new ObjectDeserializer()).create(); 
// ... 
+0

Un Javabean seguramente no es posible, ya que el conjunto de claves no es fijo. Como solución alternativa puedo usar 'Map ' y convertir los tipos manualmente (algo así), me pregunto por qué GSon se comporta de manera extraña. – maaartinus

+0

La posibilidad de convertir los tipos manualmente sugiere que conoce la estructura de datos de antemano. Entonces, el argumento de que el conjunto de claves no está arreglado es un no argumento. En cuanto a Gson, podría considerar un deserializador personalizado que determine si el valor es un número (regex, analizador, 'Long # valueOf()', etc.) y devuelve 'Long' o' String'. Consulte también http://sites.google.com/site/gson/gson-user-guide#TOC-Writing-a-Deserializer – BalusC

+0

Actualicé la respuesta con un ejemplo, puede que le resulte útil. – BalusC

-1

va a almacenar los datos en un mapa. Parece que necesita convertir el objeto al tipo que necesita.

+0

Claro que no, si el tipo era 'String' o' Integer', no podría salir 'java.lang.Object @ ...'. También lo comprobé doblemente usando 'getClass()'. – maaartinus

4
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(Object.class, new JsonDeserializer<Object>() { 
     @Override 
     public Object deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
     JsonPrimitive value = json.getAsJsonPrimitive(); 
     if (value.isBoolean()) { 
      return value.getAsBoolean(); 
     } else if (value.isNumber()) { 
      return value.getAsNumber(); 
     } else { 
      return value.getAsString(); 
     } 
     } 
    }).create(); 
-1

Si quieres una cadena JSON de Map<Object, Object>, creo json-simple es mejor opción que Gson.

Este es un breve ejemplo de http://code.google.com/p/json-simple/wiki/EncodingExamples:

//import java.util.LinkedHashMap; 
//import java.util.Map; 
//import org.json.simple.JSONValue; 

Map obj=new LinkedHashMap(); 
obj.put("name","foo"); 
obj.put("num",new Integer(100)); 
obj.put("balance",new Double(1000.21)); 
obj.put("is_vip",new Boolean(true)); 
obj.put("nickname",null); 
String jsonText = JSONValue.toJSONString(obj); 
System.out.print(jsonText); 

Resultado: {"name":"foo","num":100,"balance":1000.21,"is_vip":true,"nickname":null}

para la decodificación, se refieren a http://code.google.com/p/json-simple/wiki/DecodingExamples.

4

Actualiza a Gson 2.1. Imprime esto:

a : 1.0 
b : a 
c : 2.0 
Cuestiones relacionadas