【问题标题】:Java gson.fromJson() to POJO using Reflection causes java.lang.ClassCastExceptionJava gson.fromJson() 到 POJO 使用反射导致 java.lang.ClassCastException
【发布时间】:2016-04-21 04:02:47
【问题描述】:

我在使用 Gson 解析一些 JSON 时遇到了一个噩梦般的问题。

我试图解析的 Json 结构如下所示:

{ "user_id" : "833", "message" : "User created and registered" }

当我使用以下代码解析 Json 时:

Type response = gson.fromJson(jsonString, new TypeToken<RestResponse>(){}.getType());

我收到以下错误:

java.lang.ClassCastException: ... RestResponse 无法转换为 java.lang.reflect.Type

我正在解析成以下 POJO:

import java.lang.reflect.Type;

public class RestResponse {

    private void RestResponse() {
        // Constructor required for GSON
    }

    private StatusCode statusCode;
    private String content;
    private Object data;
    private Type output;
    private String user_id;
    private String message;
    private String error;

    public String getUserID() {
        return this.user_id;
    }
    public void setUserID(String user_id) {
        this.user_id = user_id;
    }
    public String getMessage() { return this.message; }
    public void setMessage(String message) {
        this.message = message;
    }
    public String getError() { return this.error; }
    public void setError(String error) { this.error = error; }
    public StatusCode getStatusCode() {
        return statusCode;
    }
    public void setStatusCode(StatusCode statusCode) {
        this.statusCode = statusCode;
    }
    public final String getContent() {
        return content;
    }
    public final void setContent(final String content) {
        this.content = content;
    }
    public final Object getData() {
        return data;
    }
    public final void setData(final Object data) {
        this.data = data;
    }
    public final Type getOutput() {
        return output;
    }
    public final void setOutput(final Type output) {
        this.output = output;
    }
    @Override
    public final String toString() {
        return String.format("%s", this.content);
    }
}

我返回 Type 而不是 RestResponse 对象的原因是因为我根据响应类型的类型调用回调。然后我像这样处理代码:

if (statusCode == StatusCode.SUCCESS) {
    if (requestCode == AppConstants.REQUEST_REGISTRATION) {
        if (data instanceof RestResponse) {
            RestResponse restResponse       = (RestResponse) data;
            AppDelegate delegate            = (AppDelegate) getApplicationContext();
            delegate.name                   = nameText.getText().toString();
            delegate.email                  = emailText.getText().toString();
            delegate.mobile                 = validatedFormattedNum;
            delegate.referredID             = "";
            delegate.isRegistered           = 1;
            delegate.uid                    = restResponse.getUserID();
            delegate.setInMemory();
        } else {
            if(data instanceof ApiErrorResponse) {
                ApiErrorResponse apiErrorResponse = (ApiErrorResponse) data;
                ...
                ...
                ...

任何人都想看到堆栈跟踪:

E/com.sourgun.http.AppParser: General exception encountered in parse()    com.sourgun.http.RestResponse cannot be cast to java.lang.reflect.Type
04-22 12:51:13.748 31779-31779/? W/System.err: java.lang.ClassCastException: com.sourgun.http.RestResponse cannot be cast to java.lang.reflect.Type
04-22 12:51:13.748 31779-31779/? W/System.err:     at com.sourgun.http.AppParser.parse(AppParser.java:37)
04-22 12:51:13.749 31779-31779/? W/System.err:     at com.sourgun.http.RestController.onResponse(RestController.java:85)
04-22 12:51:13.750 31779-31779/? W/System.err:     at com.sourgun.http.AsyncTaskExecutor.onPostExecute(AsyncTaskExecutor.java:66)
04-22 12:51:13.750 31779-31779/? W/System.err:     at com.sourgun.http.AsyncTaskExecutor.onPostExecute(AsyncTaskExecutor.java:14)
04-22 12:51:13.751 31779-31779/? W/System.err:     at android.os.AsyncTask.finish(AsyncTask.java:651)
04-22 12:51:13.751 31779-31779/? W/System.err:     at android.os.AsyncTask.-wrap1(AsyncTask.java)
04-22 12:51:13.752 31779-31779/? W/System.err:     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:668)
04-22 12:51:13.753 31779-31779/? W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:102)
04-22 12:51:13.753 31779-31779/? W/System.err:     at android.os.Looper.loop(Looper.java:148)
04-22 12:51:13.754 31779-31779/? W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:5422)
04-22 12:51:13.754 31779-31779/? W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
04-22 12:51:13.755 31779-31779/? W/System.err:     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
04-22 12:51:13.755 31779-31779/? W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)

【问题讨论】:

  • 什么是response?它是Type 类型的变量吗?为什么?
  • 对不起,响应是一个类型
  • 为什么是Type?为什么不是RestResponse
  • 您对异常消息有什么不明白的地方?
  • 所以@Pillar,你认为这是问题所在吗?当我在另一个类中处理响应时,它是一个类型

标签: java android json gson


【解决方案1】:

得到ClassCaseException的原因:

那是因为类JsonParsing我们调用的方法“parse” gson.fromJson(jsonString, new TypeToken(){}.getType()) 这将使用反射将字符串转换为 java 对象。

试试下面的代码:

RestResponse mRestResponse = gson.fromJson(reader, RestResponse.class)); 

查看使用 GSON 解析 JSON 的详细信息 description

通过这种方法,您可以重用 Response 类来添加任何其他附加字段,以获取您可能希望从 JSON 中提取的其他数据成员

希望对你有所帮助。

【讨论】:

  • 现在你能解释一下为什么他们得到了异常吗?
  • 使用这种方法,您可以重用 Response 类来添加任何其他附加字段,以获取您可能希望从 JSON 中提取的其他数据成员
  • 什么?我在问为什么您的解决方案不会导致ClassCastException
  • 那是因为类 JsonParsing 方法 "parse" 我们调用 gson.fromJson(jsonString, new TypeToken(){}.getType()) 它将字符串转换成 java 对象使用反射。
  • @Pillar:查看上面的评论以了解您的问题。
【解决方案2】:

你有一个 RestResponse 类,

当你这样做时:

response = gson.fromJson(jsonString, new TypeToken<RestResponse>(){}.getType());

是因为您想从 json String 中获取某种类令牌,这是错误... 您想要/需要一个对象,并且只有一个类的对象 RestResponse ,所以你需要这样做:

response = gson.fromJson(jsonString, RestResponse.class);

【讨论】:

  • 这是错误的。 Gson 具有接受 TypefromJson 重载。这主要用于允许正确反序列化泛型类型。但是它仍然可以用于非泛型类型,就像这里所做的那样。但是,您确实失去了类型安全性,这使得错误很明显java.lang.ClassCastException: ... RestResponse cannot be cast to java.lang.reflect.Type。他们将结果(RestResponse)分配给Typeresponse 变量的类型),这是不允许的。顺便说一句,这些都在 cmets 中。
【解决方案3】:

问题是 RestResponse 没有正确定义,它应该被定义为(包括 implements 类型,和一个正确的公共构造函数):

 public class RestResponse implements Type {

    public RestResponse() {}

    ...
    ...

为了简洁起见,我没有将所有导入都包含到上述原始代码中,如果我这样做可能会使事情变得更清楚。

我的“解析”类中有 2 个特定于类型 Type 的导入,一个是:java.lang.reflect.Type,另一个是 @987654321 @。 TypeToken 本质上暗示了反序列化过程会将数据编组到的 Object 的类型,该类型分配给 java.lang.reflect.Type 类型的变量。

RestResponse 类没有什么特别之处,需要导入类型的原因是我将编组后的类型存储在 java.lang.reflect.Type 类型化的类成员变量中输出”。

【讨论】:

  • 投下这个答案的用户,不知什么原因,请把答案标记为正确吗?否则,请说明您拒绝此答案的原因,因为该答案实际上是针对遇到的特定情况的正确答案。
  • 我还是一头雾水。反序列化完成后Type类型的值有什么用?
  • 所以,根据返回的类型,如果例如它是一个 RestResponse 类型,可以通过 instanceof 测试进行检查,我可以安全地将 Type 转换为具体实例,从对象访问返回的数据。如果返回的 Type 是 ApiErrorResponse 类型或任何其他类型,那么在使用 instanceof 检查并转换为具体 obj 之后,我可以根据给定对象类型中的数据采取行动。因此,我可以返回不同的对象类型并仅捕获我感兴趣的数据,这使其成为处理通过线路或输入流传入的数据的一种非常灵活的方式。
  • 那么,@Pillar 在这一切之后如何投票?有人不仅对我的问题投了反对票,而且对我的回答也投了反对票!糟透了!我希望我知道它是谁!
  • 你还没有证明需要Type,特别是。 Object 会更合适。更好的是,为您的*Response 类定义您自己的超类/超接口。在大多数情况下,使用instanceof 是一种反模式,因此无论如何您都应该避免这种情况。你上面的调用返回一个RestResponse 类型的值,所以你已经知道它是什么了。你不需要重新验证它。 Type 只应在创建类型令牌时参与。其他任何地方都不需要它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-18
  • 2018-12-27
相关资源
最近更新 更多