Room database error with Kotlin data class

I am moving to a room and I am facing a lock problem. I went through and fixed all the compile time checks from the Room library, but now I see the following error:

Entities and Pojos must have a usable public constructor. You can have an empty constructor or a constructor whose parameters match the fields (by name and type). 

This appears twice during compilation without any evidence of which class it comes from, but I was able to figure out (by removing the classes from the database) that it was one of the files. I assume this is because the main key is a string instead of Int (this is one of the two classes that uses this), but nothing in the documentation indicates that there will be a problem, and in fact the documentation shows that the lines are valid primary keys.

 @Entity(tableName = "inspections") data class Inspection( @SerializedName("id") var id: Int = 0, ... // Rest of code left off for brevity, found to not be related to the issue. 

I tried several things to try to get around this.

  • Remove the data attribute of this class to make it normal. POKO
  • Remove variables from the default constructor and put them in a class
  • Remove Ignore from an empty constructor (note that this causes another problem, Room cannot pick a constructor since multiple constructors are suitable - the default ignore Room cannot pick a constructor since multiple constructors are suitable annotation wraps around this.) This is the part that bothers me the most - removing it says " several constructors are valid, "and it says that" constructors are not valid. "

Updated: adding a few extra code snippets from my project.

build.gradle

 apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' ..... implementation 'android.arch.persistence.room:runtime:1.0.0-alpha9-1' implementation 'android.arch.persistence.room:rxjava2:1.0.0-alpha9-1' kapt 'android.arch.persistence.room:compiler:1.0.0-alpha9-1' 

Database class

 @Database(entities = arrayOf(Account::class, Category::class, Inspection::class, InspectionForm::class, InspectionFormItem::class, InspectionFormsStructure::class, InspectionItemPhoto::class, InspectionItem::class, LineItem::class, LocalPhoto::class, Rating::class, Structure::class, SupervisoryZone::class, Upload::class, User::class), version = 16) @TypeConverters(Converters::class) abstract class OrangeDatabase : RoomDatabase() { abstract fun inspectionDao(): InspectionDao abstract fun localDao(): LocalDao abstract fun ratingsDao(): RatingsDao abstract fun structureZoneDao(): StructureZoneDao abstract fun userAccountDao(): UserAccountDao } 

Converters

 class Converters { @TypeConverter fun fromTimestamp(value: Long?): Date? { return if (value == null) Date() else Date(value) } @TypeConverter fun dateToTimestamp(date: Date?): Long? { return date?.time ?: 0 } @TypeConverter fun fromStringToArray(value: String?): Array<String>? { return value?.split(",")?.toTypedArray() ?: arrayOf() } @TypeConverter fun stringToStringArray(strings: Array<String>?): String? { return strings?.joinToString(",") ?: "" } } 

Another data class

 @Entity(tableName = "users") data class User( @PrimaryKey @SerializedName("id") var id: Int = 0, ... // Rest of code left off for brevity, found to not be related to the issue. 

UserPermissions Class:

 data class UserPermissions( @SerializedName("id") var pid: Int = 0, ... // Rest of code left off for brevity, found to not be related to the issue. 
+5
source share
4 answers

The problem was extremely difficult to debug and more difficult to reproduce, but I found the problem. I used the @Embedded object, but the result that came was actually a List this object. This created problems with the Embed automatic task, and there was no ideal converter that could be written for it.

 @SerializedName("range_choices") @Embedded var rangeChoices: List<RangeChoice>? = null, 

I had to comment on this with @Ignore , and instead I will save the results of this list to my own table, and now a new range_choices table.

0
source

The problem in your case is that if you have values ​​with a null value, Kotlin will generate multiple constructors for each possible constructor.

This means that you must define a default constructor and populate it with default values.

If you want to have one more that should be ignored, you should definitely use a parent constructor with all of these options.

Example:

 @Entity(tableName = "inspections") data class Inspection( @SerializedName("id") var id: Int = 0, @PrimaryKey @SerializedName("guid") var guid: String = "", @SerializedName("score") var score: Double = 0.0, @SerializedName("notification_sent_at") var notificationSentAt: Date = Date(), var wasUploaded: Boolean = false) { @Ignore constructor() : this(0, "", 0.0, Date(), false) } 

In this case, only two constructors will be generated β€œunder the hood”. If you have values ​​with a null value, you will have all the constructors available.

Example:

 data class Test(var id: Int = 0, var testString: String? = null, var testBool : Boolean? = null) { constructor(0) } 

generates

 constructor(var id:Int) constructor() : this(0) constructor(var id:Int, var testString: String) constructor(var id:Int, var testBool: Boolean) constructor(var id:Int, var testString: String, var testBool : Boolean) // .. and so on 

Since you are looking for official documentation, you can see "Overload Generation" .

After testing your class, which works flawlessly, I found in another post that you should check if you use apply plugin: 'kotlin-kapt' in your Gradle.

Double check that you have valid type converters for your Date class. I wrote which gave out more time ago.

After transcoding your things above, he did a great job by adding the UserPermissions class:

 data class UserPermissions(var permissionid: String) 

Edit: after using your UserPermission class, everything worked fine. Please take care if you use the correct import (util.Date instead of sql.Date, for example).

Another problem is that you are using the old very complex room library.

The current version (when writing this) is

 implementation "android.arch.persistence.room:runtime:1.0.0-beta2" kapt "android.arch.persistence.room:compiler:1.0.0-beta2" implementation "android.arch.persistence.room:rxjava2:1.0.0-beta2" 

I wrote a question for a long time

+5
source

Your primary keys should be as follows using the Annotation Use Targets

 @field:PrimaryKey @field:SerializedName("guid") var guid: String = "" 

and

 @field:PrimaryKey @field:SerializedName("id") var id: Int = 0 
+1
source

Try to avoid using values ​​with a null value and make all your default value. This is the easiest way to solve this problem.

If you really want to use them, you can create a constructor containing all of them.

0
source

Source: https://habr.com/ru/post/1272668/


All Articles