3

Is it possible to map a field which is deeper in a json-response to a property in an object - in other words: transform a json which hierarchy into a flat object?

For example I would like to annotate the 'user_id' property of the Marker class with 'links.user.id'. I have looked into GSON and Jackson, but couldn't find a solution.

Json-Response for a Marker:

{
  "id": 791,
  "name": "Marker42",
  "links": {
    "user": {
      "href": "http://4242.com/users/970",
      "id": 970
  }
}

Data-Model:

public class Marker {
    @SerializedName("id")
    private int id;

    @SerializedName("name")
    private String name;

    @SerializedName("links.user.id")
    private int user_id;
}
Maradox
  • 111
  • 1
  • 2
  • 5
  • check out https://github.com/jayway/JsonPath – TooCool Jan 06 '15 at 18:18
  • Thanks, but as I understand this is for readings jsons, and not for mapping json to java-objects (via annotations). I could use it for a custom deserializer, which I would like to avoid, since I would need to write a custom deserializer for every class because this pattern of mapping occurs a lot in the project I'm working at. – Maradox Jan 06 '15 at 18:43

1 Answers1

1

This isn't pretty but you can set your own deserialiser in GSON. I am not as familiar with Jackson but this tutorial shows a very similar method: http://www.baeldung.com/jackson-deserialization

public static class MarkerGSONDeserializer implements JsonDeserializer<Marker>{

    @Override
    public Marker deserialize(JsonElement data, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
        if(!data.isJsonObject()){
            return null;
        } else {
            JsonObject obj = data.getAsJsonObject();
            Marker res = new Marker();
            res.setId(obj.get("id").getAsInt());
            res.setName(obj.get("name").getAsString());
            res.setUserId(((obj.get("links").getAsJsonObject())).get("user").getAsJsonObject()).get("id").getAsInt();
            return res;
        }
    }

}
TTransmit
  • 3,270
  • 2
  • 28
  • 43
  • Thanks for the example. I'm aware of that solution, but as you said it isn't pretty. I would need to write a custom deserializer for every class because this type of mapping happens a lot in the project I'm working on. I really hope there would be a better solution, but it seems there isn't. Maybe I could write my own annotations which support such a deep mapping, but I'm not quite sure how I could integrate such logic with gson. – Maradox Jan 06 '15 at 18:47
  • It shouldn't be too hard to write a custom parser to do what you need. You can probably leverage Jackson or GSON to help you. I saw this, which could be a starting point: http://stackoverflow.com/a/24150263/2832027 – TTransmit Jan 06 '15 at 18:52
  • I'm also assuming that you know that you can just nest classes within each other and GSON/Jackson will be fine. I'm guessing this is also too laborious. – TTransmit Jan 06 '15 at 19:06
  • Jeah, the problem is that I would need to create a lot of fake classes, which would have no use at all. Unfortunately I feel like this is the way to go, since all other solutions are hard/error-prone to maintain when changes occur (besides creating custom annotations, which I may have a look at). – Maradox Jan 06 '15 at 20:12