0

I have a JSON response that I want to deserialize using GSON. The JSON structure uses date strings as property names. How would one go about deserializing such.

{
  2015-04-23: [{
     seqNum: 1,
     distance: 13,
     start: "123 Main St"
     end: "225 Broadway"
     },
     {seqNum: 2
      distance: 21,
      start: "225 Broadway"
      end: "12 West St"
      }
   ]
}
maddesa
  • 1,014
  • 7
  • 18
  • possible duplicate of [JSON parsing using Gson for java](http://stackoverflow.com/questions/5490789/json-parsing-using-gson-for-java) – Viral Savaj Apr 26 '15 at 13:05
  • @ViralSavaj: It's not a duplicate of the question you mentioned. OP wants parse dynamically changing property names (in this case dates). The link you provided doesn't give an answer to this question. – Trinimon Apr 26 '15 at 13:31
  • May be this: http://stackoverflow.com/questions/7967995/android-using-gson-to-parse-a-response-with-dynamic-fields or that: https://sites.google.com/site/gson/gson-user-guide#TOC-Custom-Serialization-and-Deserialization helps – Trinimon Apr 26 '15 at 13:36

1 Answers1

1

In my answer I considered you can have a JSON response like that:

{
    "2015-04-23": [
        {
            "seqNum": 1,
            "distance": 13,
            "start": "123 Main St",
            "end": "225 Broadway"
        },
        {
            "seqNum": 2,
            "distance": 21,
            "start": "225 Broadway",
            "end": "12 West St"
        }
    ],

    "2015-04-24": [
            {
                "seqNum": 1,
                "distance": 13,
                "start": "123 Main St",
                "end": "225 Broadway"
            },
            {
                "seqNum": 2,
                "distance": 21,
                "start": "225 Broadway",
                "end": "12 West St"
            }
        ]
}

So the first step would be to create the appropriate classes.

class MyObject {
    private List<DateMapping> dateMappings;

    public MyObject(List<DateMapping> dateMappings) {
        this.dateMappings = dateMappings;
    }
    ...
}
class DateMapping {
    private Date date;
    private List<Sequence> sequences;

    public DateMapping(Date date, List<Sequence> sequences) {
        this.date = date;
        this.sequences = sequences;
    }
    ...
}

class Sequence {
    private int seqNum;
    private int distance;
    private String start;
    private String end;
    ...
}

Now how can you parse the keys as they are dynamic? The answer is to use a custom deserializer:

class MyObjectAdapter implements JsonDeserializer<MyObject> {

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    private static final Type listSequenceType = new TypeToken<List<Sequence>>(){}.getType();

    public MyObject deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        List<DateMapping> dateMappings = new ArrayList<>();
        for(Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
            try {
                dateMappings.add(new DateMapping(dateFormat.parse(entry.getKey()), context.deserialize(entry.getValue(), listSequenceType)));
            } catch (ParseException e) {
                e.printStackTrace();
                throw new RuntimeException("Can't parse the date");
            }
        }
        return new MyObject(dateMappings);
    }
}

From there you can see that I iterate over each entry of the top-level JsonObject from which you create a new DateMapping for each entry. Then you just have to register the adapter in the Gson parser and you're done.

Gson gson = new GsonBuilder().registerTypeAdapter(MyObject.class, new MyObjectAdapter()).create();
MyObject myObject = gson.fromJson(new FileReader(new File("myJson")), MyObject.class);

Running on the sample above produces the output:

MyObject => 
DateMapping Thu Apr 23 00:00:00 CEST 2015, sequences=[Sequence{seqNum=1, distance=13, start='123 Main St', end='225 Broadway'}, Sequence{seqNum=2, distance=21, start='225 Broadway', end='12 West St'}]
DateMapping Fri Apr 24 00:00:00 CEST 2015, sequences=[Sequence{seqNum=1, distance=13, start='123 Main St', end='225 Broadway'}, Sequence{seqNum=2, distance=21, start='225 Broadway', end='12 West St'}]

If you have only a single entry, you could skip the creation of the class MyObject, and get the first entry of the JsonObject from which you create a single DateMapping instance.

Hope it helps! :)

Alexis C.
  • 91,686
  • 21
  • 171
  • 177