Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Telling Retrofit to what variable it should map a certain json field?

The REST API I'm talking to is responding to some of the requests in a structure as such:

{
  "_links": {
    "next": "NEXT_DATA_BLOCK_URL",
    "prev": "PREV_DATA_BLOCK_URL",
    "self": "CURRENT_DATA_BLOCK_URL"
  },
  "RESPONSE_DATA_NAME": [
    {
      ... DATA_FIELDS ...
    }
  ]
}

Where 'RESPONSE_DATA_NAME' is the data "name" - changes according to desired request. for example, it might be 'teams' or 'messages'.

Therefore I created a generic class with the following members:

public class PagedResponse<T> {
  public PagingLinks _links;
  public List<T> _data;
}

Is there any way I can set up my RestAdapter so that it'll always map 'RESPONSE_DATA_NAME' to the '_data' member, no matter what the field name actually is?

Thanks ^_^

like image 201
iDaN5x Avatar asked May 07 '14 17:05

iDaN5x


2 Answers

Using gson you can annotate your _data field with the @SerializedName. The parameter (value) of this annotation is the name to be used when serialising and deserialising objects. For example, the Java field _data is represented as RESPONSE_DATA_NAME in JSON.

public class PagedResponse<T> {

    public PagingLinks _links;
    @SerializedName(value="RESPONSE_DATA_NAME")
    public List<T> _data;
}

Further see doc


If you want to control the json field then you have to write custom de-serializer as like below

public class CustomDeserializer implements JsonDeserializer<PagedResponse> {

    @Override
    public PagedResponse deserialize(final JsonElement json,
            final Type typeOfT, final JsonDeserializationContext context)
            throws JsonParseException {

        Gson gson = new Gson();
        PagedResponse pagedResponse = new PagedResponse<>();
        List list = new ArrayList<>();

        pagedResponse = gson.fromJson(json, PagedResponse.class);

        Type listType = new TypeToken<List>() {}.getType();

        Set<Entry<String, JsonElement>> enteries = json.getAsJsonObject().entrySet();
        for (Entry<String, JsonElement> entry : enteries) {
            JsonElement jsonElement = (JsonElement) entry.getValue();
            if (jsonElement.isJsonArray()) {
                list.add(gson.fromJson(jsonElement, listType));
            }
        }
        pagedResponse.set_data(list);
        return pagedResponse;

    }
}

finally parse it

 GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(PagedResponse.class, new CustomDeserializer());
Gson gson = gsonBuilder.create();

gson.fromJson(Your_JSON_STRING_HERE, PagedResponse.class);
like image 75
Asif Bhutto Avatar answered Sep 20 '22 17:09

Asif Bhutto


So I finally found a solution to the problem...

I created a costume de-serializer, which adds the data field to the existing JsonObject, and copies the content of the RESPONSE_DATA_NAME (which is a JsonArray). Then I serialize it normaly with GSON simple conversion (gson.fromJson()).

It's a bit stupid but it works =P

The de-serializer's class:

public class PagedResponseDeserializer implements JsonDeserializer<PagedResponse> {

    @Override
    public PagedResponse deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException {

        Gson gson = new Gson();
        JsonElement value = null;
        JsonObject jsonObject = json.getAsJsonObject();     

        Iterable<Entry<String,JsonElement>> entries = jsonObject.entrySet();
        for (Entry<String, JsonElement> entry : entries) {
            value = entry.getValue();
            if (value.isJsonArray()) break;
        }

        jsonObject.add("data", value);

        return gson.fromJson(jsonObject, typeOfT);      
    }
}
like image 24
iDaN5x Avatar answered Sep 19 '22 17:09

iDaN5x