画竜点睛を衝く@mapyo

日々やった事をつらつらと書くブログです

KotlinでGsonでパースした時の挙動の調査

Kotlin書いてて、基本的にはvalで宣言してかつ書けるのであればnon-nullな形で書いていくのが良い書き方だなぁと考えている。

data classでGsonを使ってパースした時に、non-nullな形で書きたい。 しかし、Jsonはnullとか、そもそもキーが欠落していたりとか、Kotlinのnon-nullでは表せない状態を取る事が出来る。 そうなった時に一体どのような挙動するのか、どのように書くとそのような挙動を吸収できるのか?疑問に思ったので試してみた。

例えば、以下のような感じで書いた時にGsonでパースした結果がどうなるかについて調べた。

NonNullで定義しているケース

data class UserNonNull(
        val id: Int,
        val name: String,
        @SerializedName("has_family")
        val hasFamily: Boolean
)

Nullableで定義しているケース

data class UserNullable(
        val id: Int?,
        val name: String?,
        @SerializedName("has_family")
        val hasFamily: Boolean?
)

パースするJsonは正常系、すべてnullが入った場合、そもそもキーがない場合の3パターン。 合計6パターンでどうなるか調べた。

検証したテストケースはこの辺にアップしているのでご覧ください。

https://github.com/mapyo/GsonKotlinSample/blob/master/app/src/test/java/com/mapyo/gsonkotlinsample/GsonSampleUnitTest.kt

結果

調べてる途中にそりゃそうだわー。と思ってきたので詳細は↑に書いてたテストケースのURLを御覧ください。 KotlinのByteCodeを表示してJavaデコンパイルするとよくわかる。

val id: Int
↓
int id;
val id: Int?
↓
Integer id;

という具合のjavaコードが生成されるからだ。Gsonでパースした結果は、Javaのそれと同じ。 intだとjsonがnullでも0になるし、Integerだとjsonがnullだとnullになる。

Stringの場合は違う。

val name: String
↓
@NotNull
String name;
val name: String?
↓
@Nullable
String name;

NotNullがついているとはいえ、jsonがnullの場合やキーがない場合は容赦なくnullになる。なので、val name: Stringで宣言してても、nullが入ってきて、それを使おうとするとぬるぽになる。

余談だが、AndroidのNullじゃないアノテーション@NonNullで表されてるけど、 KotlinをJavaに変換した時は、@NotNullという名前がつけられてるんだなぁ。

僕の意見

Gsonでパースするときは、生成されるJavaコードを意識しつつ、 Jsonでnullが入ってくるのかどうか。キーが必ずあるのかどうか。 を意識して、NonNullにするか、Nullableにするか選択しましょう。

val name: Stringとしていても、Jsonの内容によってはNullが返ってくるので注意。 これは、別のクラスや配列などをパースするようにしていても同じ事だと思う。 未検証だけど、生成されるJavaのコードの事を考えるとそうなるはず。

この辺をある程度わかった上でコードを書いてると厚みが出るかなぁと思った。そんな今日この頃。