【问题标题】:Handle unknown REST/JSON return type处理未知的 REST/JSON 返回类型
【发布时间】:2015-09-01 09:49:31
【问题描述】:

我们正在使用 Retrofit 库 v1.9.0 使用 REST 调用从我们的服务器检索 Web 服务。

问题是,我必须指定 web 服务中每个对象的返回类型,否则会抛出异常。这是一个例子:

serviceTest.testWebservice(new Callback<MessageFromWebservice>() {
            @Override
            public void success(MessageFromWebservice message, Response response) {
                Log.i(TAG, "Test returned : " + message.toString());
            }

            @Override
            public void failure(RetrofitError retrofitError) {
                Log.e(TAG, "Test error : " + retrofitError.toString());
            }
        });

我的回调在哪里

class MessageFromWebservice{
private List<Product> products;
}

所以,我的 Android 应用程序必须只检索一些产品:JSON 必须是

"{products: [
{label="Product1", price="12"},
{label="Product2", price="21"}
]}"

现在,我的服务器只能向我发送一个产品,结果 JSON 将是一个对象产品而不是一个产品数组。

"{products:{label="Product1", price="12"}}"

每当发生这种情况时,Retrofit 都会抛出异常,应用程序崩溃。

我不明白为什么 Retrofit 不能处理来自服务器的未知返回类型(同一变量中的单个对象或数组)。

错误如下,如果我的班级想要一个列表,并且网络服务返回一个产品。

retrofit.RetrofitError: com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 14 path $.products

有这个解决方案: How to handle Dynamic JSON in Retrofit?

但它似乎太复杂了,无法包含在 Retrofit 库中......

【问题讨论】:

  • 您可以使用Response 作为返回类型。您可以使用getBody 方法从Response 获取正文。
  • 请粘贴崩溃日志。
  • @Tauqir:Logcat 编辑有问题。 @Ziem:所以我可以读取 InputStream 并实例化 JSONObject 或 JSONArray ?然后我不需要使用 Retrofit 库,只需创建我的 URLConnection.openConnection() 并从中读取流?
  • Retrofit 是 HTTP 客户端,如何解析数据取决于您。如果您不喜欢 Response 类的解决方案,您可以使用 JsonDeserializeHere你可以找到例子。

标签: android json gson retrofit


【解决方案1】:

您可以为您的 Gson 转换器使用自定义 deserializer。基本思想是在响应转换为 Json 树之后,但在转换为您的对象之前拦截反序列化。在反序列化器中,检查products 字段,看它是数组还是单个对象,并酌情反序列化。这是它如何在上面查找您的对象的草图。

public class MessageSerializer implements JsonDeserializer<MessageFromWebservice> {

    @Override
    public  MessageFromWebservice deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        MessageFromWebservice message = new MessageFromWebservice();
        if(json.isJsonObject()) {
            JsonObject jsonObject = json.getAsJsonObject();
            if(jsonObject.has("products")) {
                JsonElement products = jsonObject.get("products");
                if(products.isJsonArray()) {
                    Type productListType = new TypeToken<List<Product>>(){}.getType();
                    message.products = context.deserialize(products, productListType);
                } else {
                    message.products = new ArrayList<Product>(1);
                    Product product = context.deserialize(products, Product.class);
                    message.products.add(product);
                }
            }
            return message;
         } else {
            // top level is supposed to be an object
            throw new IllegalStateException();
        }
    }
}

那么就可以创建一个自定义的Gson实例并注册上面的适配器——

Gson gson = new GsonBuilder()
                .registerTypeAdapter(MessageFromWebservice.class, new MessageSerializer())
                .create();

并在您的 RestAdapter 构建器中添加对 setConverter(new GsonConverter(gson)) 的调用。喜欢——

RestAdapter restAdapter = new RestAdapter.Builder()
                .setConverter(new GsonConverter(gson))
                //... other options
                .build();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-09-22
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多