I am trying to make my response class generic. The problem is that it returns a List with the type com.google.gson.internal.LinkedTreeMap instead of the type Brewer.
The function that starts all this:
List<Brewer> brewerList = null;
try {
Response<Brewer> responseHandler = new Response<Brewer>();
brewerList = responseHandler.getAll(response);
functionCallBack = Constants.FUNCTION_DB_BREWER;
list = brewerList.toArray(new Brewer[brewerList.size()]);
} catch (IOException e) {
Tools.LOG_ERROR(e);
}
This is my response class:
public class Response<T> {
public List<T> getAll(JSONObject response) throws IOException {
List<T> brewerList = null;
// Map JSON to JAVA Objects
Type listResponse = new TypeToken<ListResponse<T>>() {
}.getType();
ListResponse<T> responseObject = Shared.gson.fromJson(response.toString(), listResponse);
if (responseObject != null) {
// Status, Message, Data
int status = responseObject.getStatus();
Tools.LOG_DEBUG("Response - getAll, Status: " + status);
if (responseObject.getData() != null && responseObject.getStatus() == 200) {
brewerList = responseObject.getData();
} else {
Tools.LOG_DEBUG("Couldn't find the webservices!");
}
}
return brewerList;
}
}
And this is my data class that i give to parse from json
public class ListResponse<T> {
private int status;
private List<T> data;
public ListResponse() {
}
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
}
Exception:
04-11 10:54:55.994 31660-31660/be.appmax.ktsjjt E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.ArrayStoreException: source[0] of type com.google.gson.internal.LinkedTreeMap cannot be stored in destination array of type be.appmax.ktsjjt.models.Brewer[]
at java.lang.System.arraycopy(Native Method)
at java.util.ArrayList.toArray(ArrayList.java:523)
at be.appmax.ktsjjt.database.SyncHandler.onRestTaskCompleted(SyncHandler.java:96)
at be.appmax.ktsjjt.webservices.WSBrewer$1.onSuccess(WSBrewer.java:36)
at com.loopj.android.http.JsonHttpResponseHandler$1$1.run(JsonHttpResponseHandler.java:125)
at android.os.Handler.handleCallback(Handler.java:730)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:176)
at android.app.ActivityThread.main(ActivityThread.java:5419)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:525)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
at dalvik.system.NativeStart.main(Native Method)
Unfortunately you can't do what you're trying to do because of type erasure in Java.
The TypeToken
hack used by various libraries that do deserialization tries to get around this, but you can't use it with a generic type parameter as you're attempting to do. The type of T
is erased at runtime and Gson can no longer determine the actual type so ... it returns a Map
.
Edit to add: The way to get around this is to pass in the TypeToken
rather than trying to create it in the method. This allows the type to be known. The tricky bit is in your case you want to return a List<T>
but the TypeToken
is actually ListResponse<T>
. Because of that you have to get a bit creative with Generics and infer the TypeToken type with a bounding:
public <V extends ListResponse<T>> List<T> getAll(JSONObject response, TypeToken<V> token) throws IOException {
...
V responseObject =
Shared.gson.fromJson(response.toString(), token.getType());
...
}
When you call this, you'll need to pass in the TypeToken
instance, but then it will work.
Response<Brewer> responseHandler = new Response<Brewer>();
TypeToken<ListResponse<Brewer>> token = new TypeToken<ListResponse<Brewer>>(){};
brewerList = responseHandler.getAll(response, token);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With