Как разобрать ответ JSON от DuckDuckGo Ответы API с помощью Retrofit2?

Я пытаюсь получить экземпляры POJO, используя Gson и Retrofit2.

Типичный ответ JSON выглядит следующим образом.

Моя проблема с Infobox поле. В некоторых случаях (например, это) поле будет объектом следующего типа и пустой строкой в ​​противном случае.

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 в ответе, который также является объектом, в некоторых случаях будет иметь значение как ноль (а не пустую строку, такую ​​как infobox)

Я предпочел бы иметь возможность делать это с помощью Gson, поскольку я использовал это для всего остального, и я не хочу добавлять другую зависимость

2 ответа

Я закончил тем, что использовал 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);

Привет. Пожалуйста, перейдите по ссылке: http://www.jsonschema2pojo.org/ вставьте свой код. эти сайты автоматически создают все связанные с вами классы.

Если проблема, пожалуйста, посмотрите на эту ссылку.

мой диск

Другие вопросы по тегам