我正在尝试使用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,因为我已经将它用于其他所有内容而且我不想添加其他依赖项
答案 0 :(得分:0)
答案 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);