Как разобрать ответ 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/ вставьте свой код. эти сайты автоматически создают все связанные с вами классы.
Если проблема, пожалуйста, посмотрите на эту ссылку.