Roomのデータベース定義では
@Database(
entities = [Settings::class],
version = 1,
exportSchema = false
)
abstract class AppDatabase : RoomDatabase() {
abstract fun SettingsDao(): SettingsDao
:
}
エンティティやDAOの追加、削除等による列挙ミスを防止するため、列挙するエンティティやDAOを自動生成するKSPプロセッサープラグインを作成します。
エンティティやDAOの自動生成に必要なKSPライブラリをバージョンカタログに追記します。
[versions]
:
# ./gradlew -versionで表示されるKotlinのバージョンに適した最新バージョンにします(自動で上げない)
#noinspection GradleDependency,NewerVersionAvailable
gradle-ksp = "2.0.21-1.0.28" # https://mvnrepository.com/artifact/com.google.devtools.ksp/symbol-processing-api
kotlin-poet = "2.2.0" # https://mvnrepository.com/artifact/com.squareup/kotlinpoet
:
[libraries]
:
gradle-ksp = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "gradle-ksp" }
kotlin-poet = { module = "com.squareup:kotlinpoet", version.ref = "kotlin-poet" }
kotlin-poet-ksp = { module = "com.squareup:kotlinpoet-ksp", version.ref = "kotlin-poet" }
:
room-common = { module = "androidx.room:room-common", version.ref = "room" }
:
追記後、『Sync Now』で内容をプロジェクトに反映させます。
KSPプロセッサーモジュール:core:database:kspをAndroid Studioのモジュール作成ウィザードを使わずにモジュールを作成します。
/core/database直下にkspディレクトリを追加し、その直下にkotlinスクリプトbuild.gradle.ktsを作成してモジュール化します。
plugins {
alias(libs.plugins.kotlin.jvm)
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(libs.versions.java.get().toInt()))
}
}
dependencies {
implementation(libs.gradle.ksp)
implementation(libs.kotlin.poet)
implementation(libs.kotlin.poet.ksp)
implementation(libs.room.common)
}
モジュール作成ウィザードを使わずにモジュールを作成したため、ビルド対象モジュールに手動で追記します。
:
include(":core:database")
include(":core:database:ksp")
:
追記後、『Sync Now』で内容をプロジェクトに反映させます。
:core:database:kspモジュールにsrc/main/kotlinディレクトリを作成し、jp.co.progress_llc.portal.core.database.ksp.modelパッケージ(ディレクトリ)を追加します。
作成したパッケージ内にエンティティコレクター用のデータモデルEntityModel.ktを作成します。
package jp.co.progress_llc.portal.core.database.ksp.model
data class EntityModel(
val packageName: String,
val simpleName: String
) {
val qualifiedName: String = "$packageName.$simpleName"
}
modelパッケージと同階層にcollectorパッケージ(ディレクトリ)を追加します。
作成したパッケージ内にエンティティコレクターEntityCollector.ktを作成します。
package jp.co.progress_llc.portal.core.database.ksp.collector
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSClassDeclaration
import jp.co.progress_llc.portal.core.database.ksp.model.EntityModel
class EntityCollector(
private val resolver: Resolver,
private val logger: KSPLogger
) {
fun collect(): List<EntityModel> {
return resolver
.getSymbolsWithAnnotation("androidx.room.Entity")
.filterIsInstance<KSClassDeclaration>()
.map { entity ->
EntityModel(
packageName = entity.packageName.asString(),
simpleName = entity.simpleName.asString()
)
}
.toList()
}
}
modelパッケージ内にDAOコレクター用のデータモデルDaoModel.ktを作成します。
package jp.co.progress_llc.portal.core.database.ksp.model
data class DaoModel(
val packageName: String,
val simpleName: String
) {
val qualifiedName: String = "$packageName.$simpleName"
val functionName: String = simpleName.replaceFirstChar { it.lowercaseChar() }
}
collectorパッケージ内ににDAOコレクターDaoCollector.ktを作成します。
package jp.co.progress_llc.portal.core.database.ksp.collector
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.symbol.KSClassDeclaration
import jp.co.progress_llc.portal.core.database.ksp.model.DaoModel
class DaoCollector (
private val resolver: Resolver,
private val logger: KSPLogger
) {
fun collect(): List<DaoModel> {
return resolver
.getSymbolsWithAnnotation("androidx.room.Dao")
.filterIsInstance<KSClassDeclaration>()
.map { dao ->
DaoModel(
packageName = dao.packageName.asString(),
simpleName = dao.simpleName.asString()
)
}
.toList()
}
}
collectorパッケージと同階層にgeneratorパッケージ(ディレクトリ)を追加します。
追加したパッケージ内にRoomデータベースを生成するkotlinクラスファイルAppDatabase.ktを自動生成するAppDatabaseGenerator.ktを作成します。
エンティティコレクターをKSPに提供するプロバイダーRoomEntityCollectorProvider.ktを作成します。
package jp.co.progress_llc.portal.buildlogic.ksp
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
/**
* RoomEntityCollectorのプロバイダー
*/
class RoomEntityCollectorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return RoomEntityCollector(environment)
}
}
プロバイダーをKSPのサービスに登録してインスタンス化します。
:build-logic:kspモジュールの/src/mainセットにresources/META-INF/servicesディレクトリを追加し、直下にcom.google.devtools.ksp.processing.SymbolProcessorProviderを作成します。
jp.co.progress_llc.portal.buildlogic.ksp.RoomEntityCollectorProvider
エンティティコレクターをプラグインとして各エンティティ定義モジュールから呼び出せるようにします。
:build-logicモジュールのbuild.gradle.ktsにプラグインの作成に必要な依存ライブラリを追記します。
:
dependencies {
:
implementation(libs.gradle.ksp.plugin)
:
追記後、『Sync Now』で内容をプロジェクトに反映させます。
:build-logicモジュールのpluginsパッケージ(ディレクトリ)内にRoomEntityCollectorPlugin.ktを作成します。
package jp.co.progress_llc.portal.buildlogic.plugins
import org.gradle.api.Plugin
import org.gradle.api.Project
import com.google.devtools.ksp.gradle.KspExtension
/**
* RoomのEntityを自動収集するためのGradleプラグイン
*/
class RoomEntityCollectorPlugin : Plugin<Project> {
override fun apply(project: Project) {
project.plugins.apply("com.google.devtools.ksp")
project.dependencies.add(
"ksp",
"jp.co.progress_llc.portal.buildlogic:ksp:1.0.0"
)
val kspExt = project.extensions.getByType(KspExtension::class.java)
kspExt.arg("ksp.module.name", project.path)
}
}
:build-logicモジュールのbuild.gradle.ktsにエンティティコレクタープラグインを追記します。
:
gradlePlugin {
:
plugins {
register("RoomEntityCollectorPlugin") {
id = "build.logic.room.entity.collector"
implementationClass = "jp.co.progress_llc.portal.buildlogic.plugins.RoomEntityCollectorPlugin"
}
}
:
エンティティを定義している:feature:depart:dataモジュールにエンティティコレクタープラグインを適用します。
plugins {
:
id("build.logic.room.entity.collector")
:
:feature:depart:dataモジュールをビルドして、build/generated/ksp/release/kotlin/generated/room/entities/FeatureDepartDataRoomEntities.ktにエンティティクラスの配列が作成されていることを確認します。