我正在从Reddit API中检索评论。该模型具有线程,因此每个Comment都可以在内部有一个注释列表,名为回复。以下是JSON响应的外观示例:
[
{
"kind":"Listing",
"data":{
"children":[
{
"data":{
"body":"comment",
"replies":{
"kind":"Listing",
"data":{
"children":[
{
"data":{
"body":"reply to comment",
"replies":""
}
}
]
}
}
}
}
]
}
}
]
以下是我使用POJO进行模拟的方法。上面的回复将被视为CommentListings列表。
public class CommentListing {
@SerializedName("data")
private CommentListingData data;
}
public final class CommentListingData {
@SerializedName("children")
private List<Comment> comments;
}
public class Comment {
@SerializedName("data")
private CommentData data;
}
public class CommentData {
@SerializedName("body")
private String body;
@SerializedName("replies")
private CommentListing replies;
}
注意底层CommentData POJO如何引用另一个名为“replies”的CommentList。
此模型有效,直到GSON到达最后一个没有回复的子CommentData。 API不提供null,而是提供空字符串。当然,这会导致GSON异常,它需要一个对象但却找到一个String:
"replies":""
预计BEGIN_OBJECT但是STRING
我试图在CommentData类上创建自定义反序列化器,但由于模型的递归性质,它似乎没有达到模型的底层。我想这是因为我使用单独的GSON实例来完成反序列化。
@Singleton
@Provides
Gson provideGson() {
Gson gson = new Gson();
return new GsonBuilder()
.registerTypeAdapter(CommentData.class, new JsonDeserializer<CommentData>() {
@Override
public CommentData deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject commentDataJsonObj = json.getAsJsonObject();
JsonElement repliesJsonObj = commentDataJsonObj.get("replies");
if (repliesJsonObj != null && repliesJsonObj.isJsonPrimitive()) {
commentDataJsonObj.remove("replies");
}
return gson.fromJson(commentDataJsonObj, CommentData.class);
}
})
.serializeNulls()
.create();
}
如何强制GSON返回null而不是String,以便它不会尝试强制String进入我的POJO?或者,如果不可能,手动协调数据问题?如果您需要其他背景信息,请与我们联系。感谢。
答案 0 :(得分:8)
一般来说,你的代码看起来不错,但我会推荐一些东西:
Gson
个实例。类型适配器工厂(TypeAdapterFactory
)是为此目的而设计的。此外,在JSON序列化器和反序列化器中,您可以分别通过JsonSerializationContext
和JsonDeserializationContext
隐式引用它(这可以避免在某些情况下无限递归)。public final class EmptyStringAsNullTypeAdapter<T>
implements JsonDeserializer<T> {
// Let Gson instantiate it itself
private EmptyStringAsNullTypeAdapter() {
}
@Override
public T deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context)
throws JsonParseException {
if ( jsonElement.isJsonPrimitive() ) {
final JsonPrimitive jsonPrimitive = jsonElement.getAsJsonPrimitive();
if ( jsonPrimitive.isString() && jsonPrimitive.getAsString().isEmpty() ) {
return null;
}
}
return context.deserialize(jsonElement, type);
}
}
然后只需注释replies
字段:
@SerializedName("replies")
@JsonAdapter(EmptyStringAsNullTypeAdapter.class)
private CommentListing replies;