处理未知的REST / JSON返回类型

时间:2015-09-01 09:49:32

标签: android json gson retrofit

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

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

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无法处理来自服务器的未知返回类型(同一变量中的单个Object或Array)。

如果我的Class想要一个List,并且Web服务返回一个Product,则错误如下所示。

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库中......

1 个答案:

答案 0 :(得分:0)

您可以为您的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();

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

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