Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing Map<Object, Object> with GSon

Tags:

java

object

gson

I have a Map containing a mixture of types like in this simple example

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());
}

What I get back are plain Objects, no Integers, no Strings. The output looks like

a : java.lang.Object@48d19bc8
b : java.lang.Object@394a8cd1
c : java.lang.Object@4d630ab9

Can I fix it somehow? I'd expect that such simple cases will be handled correctly by default.

I know that the information about the type can't always be preserved, and possibly 1 and "1" means exactly the same in JSON. However, returning plain content-less objects just makes no sense to me.

Update: The serialized version (i.e. the string above) looks fine:

{"a":1,"b":"a","c":2}
like image 681
maaartinus Avatar asked Mar 22 '11 19:03

maaartinus


2 Answers

Gson isn't that smart. Rather provide a clear and static data structure in flavor of a Javabean class so that Gson understands what type the separate properties are supposed to be deserialized to.

E.g.

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

in combination with

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

Update: as per the comments, the keyset seems to be not fixed (although you seem to be able to convert it manually afterwards without knowing the structure beforehand). You could create a custom deserializer. Here's a quick'n'dirty example.

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;
        }
    }

}

which you use as follows:

final Gson gson = new GsonBuilder().registerTypeAdapter(Object.class, new ObjectDeserializer()).create();
// ... 
like image 92
BalusC Avatar answered Sep 18 '22 09:09

BalusC


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();
like image 21
Michael Lancaster Avatar answered Sep 18 '22 09:09

Michael Lancaster