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パターンでどうなるか調べた。
検証したテストケースはこの辺にアップしているのでご覧ください。
結果
調べてる途中にそりゃそうだわー。と思ってきたので詳細は↑に書いてたテストケースの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のコードの事を考えるとそうなるはず。
この辺をある程度わかった上でコードを書いてると厚みが出るかなぁと思った。そんな今日この頃。