【问题标题】:How to parse JSON response from DuckDuckGo Answers API using Retrofit2?如何使用 Retrofit2 解析来自 DuckDuckGo Answers API 的 JSON 响应?
【发布时间】:2016-11-16 13:32:32
【问题描述】:

我正在尝试使用 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 来完成它,因为我已经将它用于其他所有内容,并且我不想添加另一个依赖项

【问题讨论】:

  • 您好,请查看我的回答

标签: json gson retrofit2 duckduckgo-api


【解决方案1】:

您好,请转至:http://www.jsonschema2pojo.org/ 粘贴您的代码。该网站会自动创建您所有相关的课程。

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

my drive link

【讨论】:

  • 我知道这个网站。正如您在问题中看到的,我已经有 POJO 来表示 Infobox。问题是当信息框没有数据时,它返回"" 而不是null。这是两种不同的数据类型,会导致 Gson 抛出异常。
【解决方案2】:

我最终使用了JsonDeserializer。谷歌建议:

新应用应该更喜欢 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);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-08-27
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2020-08-26
    • 1970-01-01
    • 1970-01-01
    • 2018-05-26
    相关资源
    最近更新 更多