GSON deserializing key-value to custom object

deserialization, gson, java, serialization

Solution

You need to write a custom deserializer. You also need to use a time zone format that `SimpleDateFormat` can actually parse. Neither `z` nor `Z` will match `-07:00`, which is a weird mix of RFC 822 time zone format (`-0700`) or a "general time zone" (`Mountain Standard Time` or `MST` or `GMT-07:00`). Alternately, you can stick with the exact same time zone format, and use JodaTime's `DateTimeFormat`.

MyCustomClass.java

public class MyCustomClass
{
    Date date;
    Long value;

    public MyCustomClass (Date date, Long value)
    {
        this.date = date;
        this.value = value;
    }

    @Override
    public String toString()
    {
        return "{date: " + date + ", value: " + value + "}";
    }
}

MyCustomDeserializer.java

public class MyCustomDeserializer implements JsonDeserializer<MyCustomClass>
{
    private DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz");

    @Override
    public MyCustomClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) throws JsonParseException
    {
        JsonObject obj = json.getAsJsonObject();
        Entry<String, JsonElement> entry = obj.entrySet().iterator().next();
        if (entry == null) return null;
        Date date;
        try
        {
            date = df.parse(entry.getKey());
        }
        catch (ParseException e)
        {
            e.printStackTrace();
            date = null;
        }
        Long value = entry.getValue().getAsLong();
        return new MyCustomClass(date, value);
    }
}

GsonTest.java

public class GsonTest
{
    public static void main(String[] args)
    {
        // Note the time zone format tweak (removed the ':')
        String json = "[{\"2011-04-30T00:00:00-0700\":100}, {\"2011-04-29T00:00:00-0700\":200}]";

        Gson gson =
            new GsonBuilder()
            .registerTypeAdapter(MyCustomClass.class, new MyCustomDeserializer())
            .create();
        Type collectionType = new TypeToken<Collection<MyCustomClass>>(){}.getType();
        Collection<MyCustomClass> myCustomClasses = gson.fromJson(json, collectionType);
        System.out.println(myCustomClasses);
    }
}

All of the above code is on Github, feel free to clone (though you'll get code for answers to other questions as well).

Problem

I need to deserialize json which is an array of date/long values. Here is an example of the returned JSON: ``` [{"2011-04-30T00:00:00-07:00":100}, {"2011-04-29T00:00:00-07:00":200}] ``` Using GSON I am able to deserialize this to a `List<Map<Date,String>>`, but would like to be able to convert it to a `List<MyCustomClass>` similar to: ``` public class MyCustomClass() { Date date; Long value; } ``` I cannot seem to find a way to instruct GSON to map the key/value of the JSON map to the date/value fields in my custom class. Is there a way to do this, or is a list of maps the only route?

Original source

Related problems