I am in the process of writing a neat Android application to interact with the API, that follows the Google Android user experience.
The application will be using Retrofit (to make REST-api mechanisms easier).
Now, I have created Java classes that corresponds to each API call.
For example, Site.java class that handles the /sites API in this fashion:
This is condensed for brevity:
public class Site{
@SerializedName("api_site_parameter") String mApiSiteParameter = "";
// snip
}
The interface is wired up in this fashion, called ISites.java
public interface ISites{
@GET("/sites")
public void getAllSites(@Query("filter") String filterName,
Callback<List<Site>> cbAllSites);
}
The big question is, since the common wrapper is used, how can I make Retrofit return back a List<Site> collection regardless, this could equally apply to other objects such as Question, Answer and so on.
After testing with Postman extension under Chrome, I observed the following, which is a stumbling block, the common wrapper is returned in the response, regardless of which REST-api to use, however, the items field within the JSON output, contains the array of Site in this case.
I deduced, that there's a field in the common wrapper that is not returned, called type The idea here is to cheat a little bit later on... and, since it's not part of the filter, which meant having to create a new filter via /filter/create API and apply that as part of invocation to the Retrofit's RestAdapter call, as in:
RestAdapter ra = new RestAdapter.Builder()
.setServer("http://api.stackexchange.com/2.1")
.setLogLevel(LogLevel.FULL)
.build();
ISites sites = ra.create(ISites.class);
sites.getAllSites("my_commonwrapper_filter", Callback<Site>(){
@Override
public void failure(RetrofitError argRetrofitError){
}
@Override
public void success(List<Site> sites, Response response){
}
});
After studying the Gson's custom TypeAdapterFactory which was answered here on SO, am I missing something here, this is what I have so far.
Created a class called SEWrapper.java which went like this:
public class SEWrapper{
@SerializedName("items") List<Class ?> mListItems;
@SerializedName("type") String mJsonObjType;
}
Changed around the Site.java source to use SEWrapper instead of Site, and modified the REST call.
This code which is adapted from the question on StackOverflow,
private class SEWrapperTypeAdapterFactory extends CustomizedTypeAdapterFactory<SEWrapper> {
private SEWrapperTypeAdapterFactory() { super(SEWrapper.class); }
@Override
protected void beforeWrite(SEWrapper source, JsonElement toSerialize) {
// Ignored for now as all this is Read Only operation!
}
@Override
protected void afterRead(JsonElement deserialized) {
String typeOfJsonObj = deserialized.getAsJsonObject().get("type").getAsString();
if (typeOfJsonObj.equalsIgnoreCase("site")){
JsonArray jSiteArray = deserialized.getAsJsonObject().get("items").getAsJsonArray();
// Convert that to List<Site> type which I cannot figure out
}
}
Am out of ideas on how to get around this stumbling block.
I could, in theory, rewrite it to return a Retrofit's Response object and manually parse each JSON object along with creating a List of that type Site, it does feel cumbersome and long-winded for each of the API object returned.
Am I doing this the wrong way or have I set my expectations a little bit too high with the Retrofit library?