Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot find setter for field - using Kotlin with Room database

I'm integrating with the Room persistence library. I have a data class in Kotlin like:

@Entity(tableName = "story")
data class Story (
        @PrimaryKey val id: Long,
        val by: String,
        val descendants: Int,
        val score: Int,
        val time: Long,
        val title: String,
        val type: String,
        val url: String
)

The @Entity and @PrimaryKey annotations are for the Room library. When I try to build, it is failing with error:

Error:Cannot find setter for field.
Error:Execution failed for task ':app:compileDebugJavaWithJavac'.
> Compilation failed; see the compiler error output for details.

I also tried providing a default constructor:

@Entity(tableName = "story")
data class Story (
        @PrimaryKey val id: Long,
        val by: String,
        val descendants: Int,
        val score: Int,
        val time: Long,
        val title: String,
        val type: String,
        val url: String
) {
    constructor() : this(0, "", 0, 0, 0, "", "", "")
}

But this doesn't work as well. A thing to note is that it works if I convert this Kotlin class into a Java class with getters and setters. Any help is appreciated!

like image 852
gsb Avatar asked May 27 '17 05:05

gsb


4 Answers

Since your fields are marked with val, they are effectively final and don't have setter fields.

Try switching out the val with var. You might also need to initialize the fields.

@Entity(tableName = "story")
data class Story (
        @PrimaryKey var id: Long? = null,
        var by: String = "",
        var descendants: Int = 0,
        var score: Int = 0,
        var time: Long = 0L,
        var title: String = "",
        var type: String = "",
        var url: String = ""
)

EDIT

The above solution is a general fix for this error in Kotlin when using Kotlin with other Java libraries like Hibernate where i've seen this as well. If you want to keep immutability with Room, see some of the other answers which may be more specific to your case.

In some cases immutability with Java libraries is simply not working at all and while making sad developer noises, you have to switch that val for a var unfortunately.

like image 172
Jan Vladimir Mostert Avatar answered Nov 13 '22 04:11

Jan Vladimir Mostert


Hey I don't know if everyone know or not, but you can not have column which is starting from is into Room. For example you can't have like this

   @Entity(tableName = "user")
   data class User (
        @PrimaryKey var id: Long? = null,
        var userName: String = "",
        var isConnectedToFB: Boolean = false,
)
like image 29
AJay Avatar answered Nov 13 '22 02:11

AJay


There is an issue in room db library java code generation.

I was using optional field isFavorite. It gives me same error then I change my field name to favorite then compiled.

before var isFavorite: Int? = 0, after changing working fine var favorite: Int? = 0, Thanks

like image 10
Qamar Avatar answered Nov 13 '22 03:11

Qamar


According to https://stackoverflow.com/a/46753804/2914140 if you have an autogenerated primary key, you should write so:

@Entity(tableName = "story")
data class Story (
        val by: String,
        val descendants: Int,
        val score: Int,
        val time: Long,
        val title: String,
        val type: String,
        val url: String
)  {
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0
}

Note that @PrimaryKey is written inside the class body and contains modifier var.

If you later want to update a row in a database with different parameters, use these lines:

val newStory = story.copy(by = "new author", title = "new title") // Cannot use "id" in object cloning
newStory.id = story.id
dao.update(newStory)

UPDATE

I still don't use AndroidX, and Room is 'android.arch.persistence.room:runtime:1.1.1'.

You can extend this class from Serializable. But if you want to extend it from Parcelable, you will get a warning (over id variable): Property would not be serialized inro a 'Parcel'. Add '@IgnoredOnParcel' annotation to remove this warning:

enter image description here

Then I moved an id from the body to the constructor. In Kotlin I use @Parcelize to create Parcelable classes:

@Parcelize
@Entity(tableName = "story")
data class Story (
    @PrimaryKey(autoGenerate = true)
    var id: Int = 0,

    val by: String,
    val descendants: Int,
    val score: Int,
    val time: Long,
    val title: String,
    val type: String,
    val url: String
) : Parcelable
like image 8
CoolMind Avatar answered Nov 13 '22 04:11

CoolMind