Android Room Persistence library and Kotlin
Asked Answered
R

6

57

I am trying to write a simple app using Kotlin and Room Persistence Library. I followed the tutorial in the Android Persistence codelab.

Here is my AppDatabase class in Kotlin:

@Database(entities = arrayOf(User::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userModel(): UserDao

    companion object {
        private var INSTANCE: AppDatabase? = null
        @JvmStatic fun getInMemoryDatabase(context: Context): AppDatabase {
            if (INSTANCE == null) {
                INSTANCE = Room.inMemoryDatabaseBuilder(context.applicationContext, AppDatabase::class.java).allowMainThreadQueries().build()
            }
            return INSTANCE!!
        }

        @JvmStatic fun destroyInstance() {
            INSTANCE = null
        }
    }
}

But when I tried to run the app, it crashes immediately. Here is the crash log:

Caused by: java.lang.RuntimeException: cannot find implementation for com.ttp.kotlin.kotlinsample.room.AppDatabase. AppDatabase_Impl does not exist
    at android.arch.persistence.room.Room.getGeneratedImplementation(Room.java:90)
    at android.arch.persistence.room.RoomDatabase$Builder.build(RoomDatabase.java:340)
    at com.ttp.kotlin.kotlinsample.room.AppDatabase$Companion.getInMemoryDatabase(AppDatabase.kt:19)
    at com.ttp.kotlin.kotlinsample.MainKotlinActivity.onCreate(MainKotlinActivity.kt:28)
    at android.app.Activity.performCreate(Activity.java:6272)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1108)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2387)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2494) 
    at android.app.ActivityThread.access$900(ActivityThread.java:157) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1356)

It looks like the class AppDatabase_Impl wasn't autogenerated. I checked the original java app downloaded from codelab and found that AppDatabase_Impl was autogenerated.

Kotlin version: 1.1.2-3
Room version: 1.0.0-alpha1

Is there anyone experienced with this?

Edit: Using kapt solves my problem. In my case, I have to replace annotationProcessor with kapt.

Rodent answered 19/5, 2017 at 8:45 Comment(5)
Can you post your build.gradle as well?Disputatious
Is there apply plugin: 'kotlin-kapt' and kapt "android.arch.persistence.room:compiler:1.0.0-alpha1" in your module build.gradle ?Holpen
Thank you. Using kapt plugin solves my problem.Rodent
@ThanhPham i have same issue but adding kapt introduces some gradle errors, please have a look here #44143464. Can you provide your gradle file?Haematin
@chandil03 I see you just ADD the kapt. In my case, I have to REPLACE the annotationProcessor BY the kapt.Rodent
M
52

Usually in project build.gradle I define the dependencies versions:

ext {
    buildToolsVersion = '25.0.2'
    supportLibVersion = '25.3.1'
    espressoVersion = '2.2.2'
    archRoomVersion = '1.0.0-alpha1'
}

so in app build.gradle the dependencies look like:

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"

    compile "com.android.support:appcompat-v7:${rootProject.supportLibVersion}"

    compile "android.arch.persistence.room:runtime:${rootProject.archRoomVersion}"
    annotationProcessor "android.arch.persistence.room:compiler:${rootProject.archRoomVersion}"
    kapt "android.arch.persistence.room:compiler:${rootProject.archRoomVersion}"

    androidTestCompile("com.android.support.test.espresso:espresso-core:${rootProject.espressoVersion}", {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    testCompile 'junit:junit:4.12'
}

Now you can define Entities Daos and Database in Kotlin.

Database:

@Database(entities = arrayOf(User::class), version = 1)
abstract class Database : RoomDatabase() {
    abstract fun userDao(): UserDao
}

Entity:

@Entity(tableName = "user")
class User {
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
    var name: String = ""
}

Dao:

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

    @Insert
    fun insertAll(vararg users: User)

    @Delete
    fun delete(user: User)
}

NB: Query with parameters. Kotlin renames params, so the SQL query to retrieve all the emails that belong at a user via the userId is:

@Query("SELECT * FROM email "
            + "INNER JOIN user ON user.id = email.userId "
            + "WHERE user.id = :arg0")
    fun getEmailsForUser(userId: Int): List<Email>
Mythology answered 20/5, 2017 at 14:46 Comment(4)
Thank for you help. In my case, Kotlin renames params to p0, p1... instead of arg0, arg1...Rodent
@Nicola De Fiorenze i have same issue but adding kapt introduces some gradle errors, please have a look here #44143464.Haematin
How can I call the db.userDao().insertAll(user)?Benevolence
Also the apply plugin: 'kotlin-kapt' is needed in the build.gradle file as mentioned in another answer.Prudie
C
39

In my case, in build.gradle, when you have "annotationProcessor" you need to duplicate with "kapt" and it works.

compile "android.arch.persistence.room:runtime:$room_version"
annotationProcessor "android.arch.persistence.room:compiler:$room_version"
kapt "android.arch.persistence.room:compiler:$room_version"
Castora answered 21/5, 2017 at 10:45 Comment(3)
Thank you for your help.Rodent
@Castora i have same issue but adding kapt introduces some gradle errors, please have a look here #44143464.Haematin
Thank you very much sir!Alice
T
12

Try out these steps

Step 1. Set the room_version in the project.gradle file

buildscript {
    ext.kotlin_version = '1.1.51'
    ext.room_version = '1.0.0-alpha9-1'
...

Step 2. Apply the kotlin-kapt plugin in the app.gradle file, and this solved my issue.

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

android {
    compileSdkVersion 26
    buildToolsVersion "26.0.1"
...

Step 3. Add the kapt dependency in the app.gradle file

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"
    kapt "android.arch.persistence.room:compiler:$room_version"
...
}
Thanos answered 30/9, 2017 at 20:15 Comment(0)
M
4

Anyone interested in using Kotlin with Room and Data Binding can see this sample project https://github.com/entrpn/kotlin-room-databinding

Malady answered 14/8, 2017 at 18:1 Comment(0)
M
1

i almost gave up. but after doing just what dharmin007 said i also had to clean the project. that made it work. I've noticed that whenever you add kapt to gradle you MUST clean the project after synching gradle.

Munos answered 3/1, 2018 at 7:14 Comment(0)
A
0

I don't know if there is a necessity to my answer I know that some of the above answers already included this to their answers but they added other things

ONLY ADD apply plugin: 'kotlin-kapt'

Azerbaijan answered 2/2, 2019 at 13:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.