RoomのKotlinコード生成

Kenji Abe
5 min readNov 14, 2023

--

Photo by Point3D Commercial Imaging Ltd. on Unsplash

Room 2.6.0 からKSPでKotlinのコード生成が可能になりました。
Kotlinコード生成を有効にすることでの制約や変更点などをまとめておきます。

Kotlinコード生成の設定

Kotlinコード生成するにはKSPを使用する必要があります。KSPについての解説は省略しますが、詳細は公式ドキュメントなどを参考にしてください。

有効にするにはKSPの引数に以下のように設定するだけです。

ksp {
arg("room.generateKotlin", "true")
}

ビルド警告

Kotlinコード生成を有効にするとビルド時に警告がでることがあります。

例えば、以下のようなDAOの場合です。

@Query("SELECT * FROM user")
fun getAll1(): List<User>?

@Query("SELECT * FROM user")
fun getAll2(): List<User?>

1つ目のQueryでは戻り値にNullableのListを指定しています。このとき以下のような警告が表示されます。

The nullable `Collection` (kotlin.collections.List<com.example.User>?) return type in a DAO method is meaningless because Room will instead return an empty `Collection` if no rows are returned from the query.

これはListをNullableにしても意味が無いということ言っています。空の場合はnullではなくて、空のListを返すためです。

2つ目のQueryではListの型パラメータがNullableになっています。このときは以下の警告が表示されます。

The DAO method return type (kotlin.collections.List<com.example.User?>) with the nullable type argument is meaningless because for now Room will never put a null value in a result.

データがあるときはnullになることが無いため、Nullableにする必要がないということです。

この2つの警告が出ないようにするには以下のようにNonNullで定義するだけです。

@Query("SELECT * FROM user")
fun getAll(): List<User>

必要のないNullableを教えてくれるので親切になっています。

制約

Kotlinコード生成にすることで新しく制約が加わります。

以下のようにDAOを返却するプロパティが使用できなくなります。Kotlinコード生成が無効であれば、これはエラーになりません。

abstract class AppDatabase : RoomDatabase() {
abstract val userDao: UserDao  // プロパティにできない
}

以下のようなビルドエラーになります。

[ksp] Property getter overrides are not support when generating Kotlin code, please rewrite as an abstract function. - com.example.AppDatabase.getUserDao()

これは単純に関数にするだけで解決できます。

abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao // プロパティから関数に変更する
}

NonNullの注意

例えば、以下のようなQueryを定義するときはクラッシュする可能性があります。1件のみ取得するようなQueryですね。

@Query("SELECT * FROM user WHERE id = 1")
fun getUserStream(): Flow<User>

@Query("SELECT * FROM user WHERE id = 1")
fun getUser(): User

Kotlinはnullに厳密なので、レコードが0件のときは取得しただけで即クラッシュすることになります。
(とはいえ、Kotlinコード生成じゃない場合でも取得した結果がnullになってるので何にせよ注意が必要です)

1件のみ取得するようなQueryを定義するときはNullableにするようにしましょう。

@Query("SELECT * FROM user WHERE id = 1")
fun getUserStream(): Flow<User?>

@Query("SELECT * FROM user WHERE id = 1")
fun getUser(): User?

value classのサポート

Kotlinコード生成にすることでEntityのプロパティに value class を使用することができるようになります。

@JvmInline
value class UserId(val id: Int)

@Entity
data class User(
@PrimaryKey val id: UserId,
val name: String
)

--

--

Kenji Abe
Kenji Abe

Written by Kenji Abe

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO

Responses (1)