如何使用Retrofit2解析DuckDuckGo Answers API的JSON响应?

时间:2016-07-13 19:52:02

标签: json gson retrofit2 duckduckgo-api

我正在尝试使用Gson和Retrofit2获取POJO实例。

典型的JSON响应看起来像this

我的问题在于Infobox字段。在某些情况下,(如this)字段将是以下类型的对象,否则为空字符串。

class Infobox {
    public List<Content> content = new ArrayList<>();
    public List<Metum> meta;
}

class Content {
    public String dataType;
    public String value;
    public String label;
    public Integer wikiOrder;
}

class Metum {
    public String dataType;
    public String value;
    public String label;
}

我尝试编写一个TypeAdapter,如下所示

class InfoboxAdapter extends TypeAdapter<Infobox> {
    final Gson embedded = new Gson();

    @Override
    public void write(JsonWriter out, Infobox infobox) throws IOException {
        if (infobox == null) {
            out.nullValue();
            return;
        }
        out.beginObject();
        out.name("content");
        embedded.toJson(embedded.toJsonTree(infobox.content), out);

        out.name("meta");
        embedded.toJson(embedded.toJsonTree(infobox.meta), out);
        out.endObject();
    }

    @Override
    public Infobox read(JsonReader in) throws IOException {
        if ("".equals(in.peek())) {
            return null;
        }

        return embedded.fromJson(in, Infobox.class);
    }

但它失败了java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING

更令人困惑的事实是,响应中的字段meta(也是对象)在某些情况下会将值设置为null(而不是像infobox这样的空字符串)

我更喜欢能够使用Gson,因为我已经将它用于其他所有内容而且我不想添加其他依赖项

2 个答案:

答案 0 :(得分:0)

您好请访问:http://www.jsonschema2pojo.org/ 粘贴你的代码。这些网站会自动创建您所有相关的课程。

如果有问题,请查看此链接。

my drive link

答案 1 :(得分:0)

我最终使用JsonDeserializer。 Google建议:

  

新应用程序应该更喜欢TypeAdapter,其流API比此接口的树API更有效。

但我没有注意到对我的使用有任何性能影响。我有一天可能会重写这个以使用TypeAdapter,但这对我来说是有用的

class InfoboxDeserialiser implements JsonDeserializer<Infobox> {

    @Override
    public Infobox deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        try {
            if (json.isJsonNull() || json.isJsonPrimitive()) {
                return null;
            }

            JsonObject jsonObject = json.getAsJsonObject();

            Infobox infobox = new Infobox();

            JsonArray jsonContent = jsonObject.get("content").getAsJsonArray();
            JsonArray jsonMeta = jsonObject.get("meta").getAsJsonArray();

            infobox.content = new Content[jsonContent.size()];
            for (int i = 0; i < jsonContent.size(); i++) {
                infobox.content[i] = context.deserialize(jsonContent.get(i), Content.class);
            }

            infobox.meta = new Metum[jsonMeta.size()];
            for (int i = 0; i < jsonMeta.size(); i++) {
                infobox.meta[i] = context.deserialize(jsonContent.get(i), Metum.class);
            }

            return infobox;
        } catch (Exception e) {
            Timber.e(e, "Failed to deserialise the infobox");
            return null;
        }
    }
}

课程如下

class Metum {
    public String dataType;
    public String value;
    public String label;
}

class Content {
    public String dataType;
    public String value;
    public String label;
    public Integer wikiOrder;
}

我在创建服务对象时注册了这个反序列化器

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Infobox.class, new InfoboxDeserialiser());
GsonConverterFactory converterFactory = GsonConverterFactory.create(gsonBuilder.create());
        Retrofit.Builder builder = new Retrofit.Builder()
        .baseUrl("https://api.duckduckgo.com/")
        .addConverterFactory(converterFactory);