问题
EDIT After experimenting for a while, I know my problem is. I can't put generic type inside TypeToken (Type type = new TypeToken<CustomResponse<T>>(){}.getType();). When I change T into POJOA, I can run my app just fine to deserialize json into POJOA, but not into POJOB and POJOC.
How do I put generic type into TypeToken? Or, is it possible to do something like this:
if (T == POJOA) {
Type type = new TypeToken<CustomResponse<POJOA>>(){}.getType();
} else if (T == POJOB) {
Type type = new TypeToken<CustomResponse<POJOB>>(){}.getType();
} else if (T == POJOC) {
Type type = new TypeToken<CustomResponse<POJOC>>(){}.getType();
};
Previous Question: Why do parseNetworkResponse return nothing when using parametrized type?
I suspect the error is in return (Response<T>) Response.success(gson.fromJson(json, typeOfT), HttpHeaderParser.parseCacheHeaders(response)); part, because it could print Log.d("CustomRequest", json); on previous line. (please look at My GsonRequest)
My POJO
public class CustomResponse<T> {
T response;
public CustomResponse(T response) {
this.response = response;
}
public T getResponse() {
return response;
}
}
My custom deserializer
public class POJOADeserializer implements JsonDeserializer<CustomResponse<POJOA>> {
@Override
public CustomResponse<POJOA> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
//some deserializing thing
return new CustomResponse<POJOA>();
}
}
public class POJOBDeserializer implements JsonDeserializer<CustomResponse<POJOB>> {
@Override
public CustomResponse<POJOB> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
//some deserializing thing
return new CustomResponse<POJOB>();
}
}
public class POJOCDeserializer implements JsonDeserializer<CustomResponse<POJOC>> {
@Override
public CustomResponse<POJOC> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
//some deserializing thing
return new CustomResponse<POJOC>();
}
}
My GsonRequest
public class CustomRequest<T> extends JsonRequest<T> {
private final Gson gson;
private final Type typeOfT
private final Response.Listener<T> listener;
public CustomRequest(int method,
String url,
Type typeOfT,
JSONObject params,
Response.Listener<T> listener,
Response.ErrorListener errorListener) {
super(method, url, params.toString(), listener, errorListener);
this.typeOfT = typeOfT;
this.listener = listener;
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(new TypeToken<CustomResponse<POJOA>>(){}.getType(), new POJOADeserializer());
gsonBuilder.registerTypeAdapter(new TypeToken<CustomResponse<POJOB>>(){}.getType(), new POJOBDeserializer());
gsonBuilder.registerTypeAdapter(new TypeToken<CustomResponse<POJOC>>(){}.getType(), new POJOCDeserializer());
this.gson = gsonBuilder.create();
}
@Override
protected void deliverResponse(T response) {
listener.onResponse(response);
}
@Override
protected Response<T> parseNetworkResponse(NetworkResponse response) {
try {
String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
Log.d("CustomRequest", json);
return (Response<T>) Response.success(gson.fromJson(json, typeOfT), HttpHeaderParser.parseCacheHeaders(response));
} catch (UnsupportedEncodingException e) {
return Response.error(new ParseError(e));
} catch (JsonSyntaxException e) {
return Response.error(new ParseError(e));
}
}
}
The actual calling
public <T> void get(String url,
Response.Listener<CustomResponse<T>> listener,
Response.ErrorListener errorListener) {
Type type = new TypeToken<CustomResponse<T>>(){}.getType();
CustomRequest<CustomResponse<T>> request = new CustomRequest<>(Request.Method.GET, url, type, null, listener, errorListener);
Volley.newRequestQueue(context.getApplicationContext()).add(request);
}
public void getResponse() {
String url = //some url;
get(url, new Response.Listener<CustomResponse<POJOA>>() {
@Override
public void onResponse(CustomResponse<POJOA> response) {
//do something
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//do something
}
});
}
I can print Log.d("CustomRequest", json);
so that means I get the json response just fine.
The problem is return (Response<T>) Response.success(gson.fromJson(json, typeOfT), HttpHeaderParser.parseCacheHeaders(response));.
Is it error when casting to (Response<T>).
Or is it error on gson.fromJson(json, typeOfT)
回答1:
You have to specify the Type explicitly. There's type erasure in Java, which basically means that at runtime all instances of T are replaced with Object.
You should either write three different deserializers for different response types(POJOA, POJOB, POJOC) or write a generic one. Something like this should work:
public class GenericConverter implements JsonDeserializer<CustomResponse<?>> {
private Type typeOfResponse;
public GenericConverter(Type typeOfResponse) {
this.typeOfResponse = typeOfResponse;
}
public CustomResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) {
CustomResponse response = new CustomResponse();
response.setResponse(ctx.deserialize(json.getAsJsonObject().get("response"), typeOfResponse));
return response;
}
}
And register it appropriately:
gsonBuilder.registerTypeAdapter(new TypeToken<CustomResponse<POJOA>>(){}.getType(),
new GenericConverter(POJOA.class));
gsonBuilder.registerTypeAdapter(new TypeToken<CustomResponse<POJOB>>(){}.getType(),
new GenericConverter(POJOB.class));
gsonBuilder.registerTypeAdapter(new TypeToken<CustomResponse<POJOC>>(){}.getType(),
new GenericConverter(POJOC.class));
来源:https://stackoverflow.com/questions/29873650/how-do-i-put-generic-type-for-gsons-typetoken