【问题标题】:GSON: knowing what type of object to convert to?GSON:知道要转换成什么类型​​的对象?
【发布时间】:2011-01-31 04:54:14
【问题描述】:

我正在考虑将 Google 的 GSON 用于我的 Android 项目,该项目将从我的网络服务器请求 JSON。返回的 JSON 将是...

1) 已知类型的成功响应(例如:“用户”类):

{
    "id":1,
    "username":"bob",
    "created_at":"2011-01-31 22:46:01",
    "PhoneNumbers":[
        {
            "type":"home",
            "number":"+1-234-567-8910"
        },
        {
            "type":"mobile",
            "number":"+1-098-765-4321"
        }
    ]
}

2.) 不成功的响应,将始终采用以下相同的基本结构。

{
    "error":{
        "type":"Error",
        "code":404,
        "message":"Not Found"
    }
}

我希望 GSON 转换为正确的类型,具体取决于上述 error 键/值对的存在。我能想到的最实用的方法如下,但我很好奇是否有更好的方法。

final String response = client.get("http://www.example.com/user.json?id=1");
final Gson gson = new Gson();

try {
    final UserEntity user = gson.fromJson(response, UserEntity.class);
    // do something with user
} catch (final JsonSyntaxException e) {
    try {
        final ErrorEntity error = gson.fromJson(response, ErrorEntity.class);
        // do something with error
    } catch (final JsonSyntaxException e) {
        // handle situation where response cannot be parsed
    }
}

这实际上只是伪代码,因为在第一个捕获条件中,我不确定如何测试密钥 error 是否存在于 JSON 响应中。所以我想我的问题是双重的:

  1. 我可以/我如何使用 GSON 来测试密钥的存在,并据此决定如何解析?
  2. 这是其他处于类似情况的 GSON 正在做的事情,还是有更好的方法?

【问题讨论】:

    标签: java json gson


    【解决方案1】:

    您通常想要做的是让您的服务器返回一个实际的错误代码以及 JSON 错误响应。然后,如果收到错误代码,则将响应读取为 ErrorEntity,如果收到 200,则读取为 UserEntity。显然,这需要更多处理与服务器通信的细节,而不仅仅是将 URL 转换为字符串,但就是这样。

    也就是说,我相信另一种选择是使用自定义 JsonDeserializer 和一个可以返回值或错误的类。

    public class ValueOrErrorDeserializer<V> implements JsonDeserializer<ValueOrError<V>> {
      public ValueOrError<V> deserialize(JsonElement json, Type typeOfT,
                                         JsonDeserializationContext context) {
        JsonObject object = json.getAsJsonObject();
        JsonElement error = object.get("error");
        if (error != null) {
          ErrorEntity entity = context.deserialize(error, ErrorEntity.class);
          return ValueOrError.<V>error(entity);
        } else {
          Type valueType = ((ParameterizedType) typeOfT).getActualTypeArguments()[0];
          V value = (V) context.deserialize(json, valueType);
          return ValueOrError.value(value);
        }
      }
    }
    

    然后你就可以做这样的事情了:

    String response = ...
    ValueOrError<UserEntity> valueOrError = gson.fromJson(response,
        new TypeToken<ValueOrError<UserEntity>>(){}.getType());
    if (valueOrError.isError()) {
      ErrorEntity error = valueOrError.getError();
      ...
    } else {
      UserEntity user = valueOrError.getValue();
      ...
    }
    

    我还没有尝试过该代码,我仍然建议使用 HTTP 错误代码,但它为您提供了一个示例,说明如何使用 JsonDeserializer 来决定如何处理某些 JSON。

    【讨论】:

    • 错误代码更改应该很简单,因为我配置了我的网络应用程序。我将不得不玩弄并弄清楚是否删除生成的 JSON 中的“错误”键或使用类似上面的东西对我来说会更好。非常感谢您的详细回答,非常感谢!
    • 为了跟进,我确保我的 Web 服务器不会在预期出现错误响应时返回 HTTP 状态 200,并且我将 JSON 错误响应更改为不包含封装的“错误”键,仅包括“类型”、“代码”和“消息”。现在一切都按照我的意愿工作。感谢您的帮助!
    • 差不多,不过它JsonDeserializer是一个接口,所以你需要实现它,而不是扩展它。
    • 什么是 ValueOrError 类?
    • @alvinm93:它只是一个简单的值对象,可能包含T 或ErrorEntity。似乎不值得写出来。
    猜你喜欢
    • 2011-02-10
    • 2013-06-02
    • 2013-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-27
    • 2016-11-04
    相关资源
    最近更新 更多