【问题标题】:How do I put generic type for Gson's TypeToken?如何为 Gson 的 TypeToken 放置泛型类型?
【发布时间】:2015-04-26 04:14:30
【问题描述】:

编辑经过一段时间的实验,我知道我的问题是。我不能将泛型类型放入TypeToken (Type type = new TypeToken<CustomResponse<T>>(){}.getType();)。当我将T 更改为POJOA 时,我可以运行我的应用程序将json 反序列化为POJOA,但不能将其反序列化为POJOBPOJOC

如何将泛型类型放入 TypeToken?或者,是否可以这样做:

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();
};

上一个问题:为什么parseNetworkResponse在使用参数化类型时什么都不返回?

我怀疑错误出现在return (Response&lt;T&gt;) Response.success(gson.fromJson(json, typeOfT), HttpHeaderParser.parseCacheHeaders(response)); 部分,因为它可以在上一行打印Log.d("CustomRequest", json);。 (请查看我的 GsonRequest

我的 POJO

public class CustomResponse<T> {
  T response;

  public CustomResponse(T response) {
    this.response = response;
  }

  public T getResponse() {
    return response;
  }
}

我的自定义反序列化器

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>();
    }
}

我的 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));
        }
    }
}

实际调用

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
    }
  });
}

我可以打印Log.d("CustomRequest", json);

这意味着我得到了 json 响应就好了。

问题是return (Response&lt;T&gt;) Response.success(gson.fromJson(json, typeOfT), HttpHeaderParser.parseCacheHeaders(response));

转换为(Response&lt;T&gt;) 时是否出错。

或者是gson.fromJson(json, typeOfT)上的错误

【问题讨论】:

  • 如果你可以看到json文本但是在这里反序列化失败 Response.success(gson.fromJson(json, typeOfT) 那么很可能是json的预期类型和真实类型不匹配. 我使用 Volley,我发现 Google 的自定义 GsonRequest 教程非常令人困惑。所以我只发送一个 StringRequest,我可以使用 gson.fromJson 解析其字符串响应,而不需要所有复杂性。
  • 是的,现在我使用JsonObjectRequest 检索它,然后使用gson 将其解析为适当的POJO,然后将其提供给调用者。它工作正常。我只是尝试使用GsonRequest,这样我就不需要做两个任务(检索json并解析成POJO)。看来我们需要在TypeToken 中显式声明某些内容,因为当我使用new TypeToken&lt;CustomResponse&lt;POJOA&gt;&gt; 时,它可以工作,但是当我将它移动到泛型方法并在其中使用new TypeToken&lt;CustomResponse&lt;T&gt;&gt; 时,它就不起作用了。
  • 现在看来我的问题了。我应该在new TypeToken&lt;CustomResponse&lt;T&gt;&gt;(){}.getType(); 中明确声明 T。当我将T 更改为POJOA 时,我可以正常运行我的应用程序。问题是我无法为POJOBPOJOC 解析它。我需要重新表述我的问题。

标签: android json gson android-volley


【解决方案1】:

您必须明确指定Type。 Java中有type erasure,这基本上意味着在运行时T的所有实例都替换为Object

您应该为不同的响应类型(POJOAPOJOBPOJOC)编写三个不同的反序列化器,或者编写一个通用的反序列化器。像这样的东西应该可以工作:

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;
    }
}

并适当注册:

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));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-27
    • 1970-01-01
    • 2014-01-13
    相关资源
    最近更新 更多