Gson 空字串陣列例外處理 紙條

案例:

class Post {
List<Comment> comments;
  // ..
}

預期 json:

{
"msg": "Hello, world!",
  "comments": [
{ "msg": "Hello, world!" },
{ "msg": "Hello, world!" },
{ "msg": "Hello, world!" }
]
}

comments 可以是 null, [] 都可以,但是..

搗蛋 json:

{
"msg": "Hello, world!",
  "comments": ""
}

錯誤訊息:

com.github.yongjhih.MainTest > testEmptyStringArrayWithGson FAILED
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 24 path $[0].comments
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:220)
at com.google.gson.internal.bind.TypeAdapterRuntimeTypeWrapper.read(TypeAdapterRuntimeTypeWrapper.java:40)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:82)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at com.google.gson.Gson.fromJson(Gson.java:879)
at com.google.gson.Gson.fromJson(Gson.java:844)
at com.google.gson.Gson.fromJson(Gson.java:793)
at com.github.yongjhih.MainTest.testEmptyStringArrayWithGson(MainTest.java:78)
Caused by:
java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 24 path $[0].comments
at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:351)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$1.read(ReflectiveTypeAdapterFactory.java:116)
at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:216)
... 7 more

首先,我們不能只是把錯誤訊息接起來,因為這樣這則貼文不就捨棄了嗎?就只是留言有問題。

稍微查一下 ,StackOverflow 上大多是只針對 Post.class 寫一個專屬的 PostDeserializer ,這樣其實很不聰明阿,萬一 Comment 內也有類似的狀況不就寫不完了嗎?

所以我覺得寫一個通用的 ListDeserailizer 比較好:

Gson gson = new GsonBuilder().registerTypeHierarchyAdapter(List.class, new EmptyListDeserializer()).create();
Post post = gson.fromJson(json, Post.class);

這樣就搞定囉。

p.s. 雖然我本身不是 Gson 的愛用者,不過有時仍須維護 Gson downstream Orz..

後記

發現原來有人也寫過這個阿… 應該直接把 Gson 上游改好才對, PR?

See Also