Room cannot pick a constructor since multiple constructors are suitable error
Asked Answered
B

10

24

I try to implement persistent library in my android kotlin project, but catch this error on compile time:

error: Room cannot pick a constructor since multiple constructors are suitable. Try to annotate unwanted constructors with @Ignore.

Error code:

@Entity
data class Site(
        var name: String = "",
        var url: String = "",
        @PrimaryKey(autoGenerate = true) var id: Long = 0)
Billingsgate answered 19/6, 2017 at 0:39 Comment(0)
B
15

I had this error because Kotlin apparently generates multiple Java constructors for a single Kotlin constructor with default argument values. Working code see next:

@Entity
data class Site(
        var name: String,
        var url: String,
        @PrimaryKey(autoGenerate = true) var id: Long)
Billingsgate answered 19/6, 2017 at 0:39 Comment(2)
can we make secondary constructor for this data class?Dogmatic
you can try Emanuel's answer https://mcmap.net/q/550537/-room-cannot-pick-a-constructor-since-multiple-constructors-are-suitable-errorBillingsgate
L
11

None of the above solutions are good, since they work but may cause errors.

Kotlin's Data Class generates several Methods using the default constructor. That means that equals(), hashCode(), toString(), componentN() functions and copy() is generated using the attributes you assign to your constructor.

Using the above solutions like

@Entity data class Site(@PrimaryKey(autoGenerate = true) var id: Long) {
    @Ignore constructor() : this(0)
    var name: String = ""
    var url: String = ""
} 

generates all the above listed methods only for id. Using equals leads to unwanted quality, same as toString(). Solving this requires you to have all attributes you want to process inside the constructor and add a second constructor using ignore like

@Entity data class Site(
    @NonNull @PrimaryKey(autoGenerate = true) var id: Long,
    var name: String = "",
    var url: String = "") {
    @Ignore constructor(id = 0, name = ", url = "") : this()
} 

You should really keep in mind, that you usually use data classes to have methods like toString and copy. Only this solution is working to avoid unwanted bugs during runtime.

Limann answered 2/10, 2017 at 13:54 Comment(2)
I think instead of writing a separator constructor we can also use @JvmOverloads annotation.Caras
Dont use JvmOverloads if you dont need them. The generated code will be not as efficient as it would be by creating several constructors.Limann
C
2

This worked for me:

@Entity
data class Site(
    @PrimaryKey(autoGenerate = true) var id: Long = 0),
    var name: String = "",
    var url: String = "",
    @Ignore var ignored: String? = null
)
Condescension answered 30/6, 2017 at 18:41 Comment(2)
It's important to note that while this works, the ignored property will not be added to the DB, which might not be what the person who asked the question is trying to do.Unsatisfactory
@damia-fuentes It worked because the Room processor knows you are using @ Ignore in one of @ Entity properties, so, it thinks you are sure about which constructors you need. You can also use @ Ignore private var to make it more transparent in your code.Officiate
K
1

this works for me

@Entity
data class TaskDetail @Ignore constructor(
    @PrimaryKey(autoGenerate = true)
    var id:Long = 0,
    var taskId:Long = 0,
    var content:String = "")
{
    constructor():this(id = 0)
}

I use @Ignore to forbid ROOM warning

There are multiple good constructors and Room will pick the no-arg constructor. You can use the @Ignore annotation to eliminate unwanted constructors.

And add a default constructor for ROOM.

Kingfisher answered 28/6, 2018 at 10:30 Comment(0)
G
1
@Entity
data class Site @JvmOverloads constructor(
    @ColumnInfo(name = "name") var name: String = "",
    @ColumnInfo(name = "url") var url: String = "",
    @PrimaryKey(autoGenerate = true) var id: Long = 0)

Immutable model class for a Site. In order to compile with Room, we could use @JvmOverloads to handle multiple constructors.

Gehring answered 19/6, 2019 at 6:8 Comment(0)
P
1

I fix this issue by upgrading my Room and other dependency.

Just try to update all of your dependancy it should work without any change.

Thank you

Pontiff answered 10/5, 2022 at 9:19 Comment(0)
U
0

Here you change your app database version and restart program agian, it will work:

@Database(entities = arrayOf(Site::class), version = 123) abstract class YourAppDatabase : RoomDatabase() {
    abstract fun yourDao(): YourDao
}

and you can also try this data class:

    @Entity
    data class Site(@PrimaryKey(autoGenerate = true) var id: Long) {
    @Ignore constructor() : this(0)
    var name: String = "",
    var url: String = "",
}

and the last instruction: your primary key id should be incremented manually.

Hope that works for you. :)

Test to show that above answers are invalid.

data class TestModel(var id: Int = 0) {
    constructor() : this(0)

    var name: String = "defaultname"
    var testData: String = "defaulttestData"
}

val testModel = TestModel(5)
testModel.name = "test"

val testModel2 = TestModel(5)
testModel2.testData = "testdata"
testModel2.name = "test"

info { "Test with name set: $testModel" }
info { "Testdata equals Testdata2 ${testModel.equals(testModel2)}" }

returns Test with name set: TestModel(id=5) and Testdata equals Testdata2 true

Utgardloki answered 2/7, 2017 at 7:59 Comment(1)
please remove the last comma , and with @PrimaryKey(autoGenerate = true) this configuration, you can always set id = 0. :)Utgardloki
D
0

Just leaving my answer in case that helps anyone. I ran into the same issue, none of the answers above worked. The only thing that worked was changing from a data class to a class. I invite anyone to try the same code and explain why It did the trick:

Before

@Entity
data class ImgurGalleryPost (
    @NotNull @PrimaryKey
    var id: String,
    var title: String?,
    var description: String?,
    var datetime: Int?,
    var cover: String?,
    var coverWidth: Int?,
    var coverHeight: Int?,
    var accountUrl: String?,
    var accountId: Int?,
    var privacy: String?,
    var layout: String?,
    var views: Int?,
    var link: String?,
    var ups: Int?,
    var downs: Int?,
    var points: Int?,
    var score: Int?,
    var isAlbum: Boolean?,
    var vote: Boolean?,
    var favorite: Boolean?,
    var nsfw: Boolean?,
    var section: String?,
    var commentCount: Int?,
    var favoriteCount: Int?,
    var topic: String?,
    var topicId: Int?,
    var imagesCount: Int?,
    var inGallery: Boolean?,
    var isAd: Boolean?,
    @NotNull @Ignore
    var tags: List<ImgurGalleryTag>,
    var inMostViral: Boolean?,
    @NotNull @Ignore
    var images: List<ImgurGalleryImage>
)

After

@Entity
class ImgurGalleryPost (
    @NotNull @PrimaryKey
    var id: String,
    var title: String?,
    var description: String?,
    var datetime: Int?,
    var cover: String?,
    var coverWidth: Int?,
    var coverHeight: Int?,
    var accountUrl: String?,
    var accountId: Int?,
    var privacy: String?,
    var layout: String?,
    var views: Int?,
    var link: String?,
    var ups: Int?,
    var downs: Int?,
    var points: Int?,
    var score: Int?,
    var isAlbum: Boolean?,
    var vote: Boolean?,
    var favorite: Boolean?,
    var nsfw: Boolean?,
    var section: String?,
    var commentCount: Int?,
    var favoriteCount: Int?,
    var topic: String?,
    var topicId: Int?,
    var imagesCount: Int?,
    var inGallery: Boolean?,
    var isAd: Boolean?,
    @NotNull @Ignore
    var tags: List<ImgurGalleryTag>,
    var inMostViral: Boolean?,
    @NotNull @Ignore
    var images: 

List<ImgurGalleryImage>
    )

It's really weird, but I doubt that is an Android Studio cache issue because changing it back to the data class causes the error to show up again. Seems that is some kind of issue with the collection fields. I checked the constructor in the generated class and It looked fine, I don't know why the build was failing even when the constructor was being generated properly:

public ImgurGalleryPost(@org.jetbrains.annotations.NotNull()
java.lang.String id, @org.jetbrains.annotations.Nullable()
java.lang.String title, @org.jetbrains.annotations.Nullable()
java.lang.String description, @org.jetbrains.annotations.Nullable()
java.lang.Integer datetime, @org.jetbrains.annotations.Nullable()
java.lang.String cover, @org.jetbrains.annotations.Nullable()
java.lang.Integer coverWidth, @org.jetbrains.annotations.Nullable()
java.lang.Integer coverHeight, @org.jetbrains.annotations.Nullable()
java.lang.String accountUrl, @org.jetbrains.annotations.Nullable()
java.lang.Integer accountId, @org.jetbrains.annotations.Nullable()
java.lang.String privacy, @org.jetbrains.annotations.Nullable()
java.lang.String layout, @org.jetbrains.annotations.Nullable()
java.lang.Integer views, @org.jetbrains.annotations.Nullable()
java.lang.String link, @org.jetbrains.annotations.Nullable()
java.lang.Integer ups, @org.jetbrains.annotations.Nullable()
java.lang.Integer downs, @org.jetbrains.annotations.Nullable()
java.lang.Integer points, @org.jetbrains.annotations.Nullable()
java.lang.Integer score, @org.jetbrains.annotations.Nullable()
java.lang.Boolean isAlbum, @org.jetbrains.annotations.Nullable()
java.lang.Boolean vote, @org.jetbrains.annotations.Nullable()
java.lang.Boolean favorite, @org.jetbrains.annotations.Nullable()
java.lang.Boolean nsfw, @org.jetbrains.annotations.Nullable()
java.lang.String section, @org.jetbrains.annotations.Nullable()
java.lang.Integer commentCount, @org.jetbrains.annotations.Nullable()
java.lang.Integer favoriteCount, @org.jetbrains.annotations.Nullable()
java.lang.String topic, @org.jetbrains.annotations.Nullable()
java.lang.Integer topicId, @org.jetbrains.annotations.Nullable()
java.lang.Integer imagesCount, @org.jetbrains.annotations.Nullable()
java.lang.Boolean inGallery, @org.jetbrains.annotations.Nullable()
java.lang.Boolean isAd, @org.jetbrains.annotations.NotNull()
java.util.List<com.kimboo.core.model.ImgurGalleryTag> tags, @org.jetbrains.annotations.Nullable()
java.lang.Boolean inMostViral, @org.jetbrains.annotations.NotNull()
java.util.List<com.kimboo.core.model.ImgurGalleryImage> images) {
    super();
}

If anyone can figure out a way to fix this without changing from data class to class please feel free to comment below.

Doublefaced answered 15/6, 2018 at 3:14 Comment(1)
More info: Seems that Room won't ignore the @Ignore arguments if they're in the constructor issuetracker.google.com/issues/70762008Doublefaced
K
0

Try to change the variable datatype from val to var :

BEFORE :

 @Entity
    data class Product(
            @PrimaryKey
            val id: String = "",
            val name: String = ""
    )

AFTER :

@Entity
data class Product(
        @PrimaryKey
        var id: String = "",
        var name: String = ""
)
Keown answered 19/12, 2018 at 6:42 Comment(0)
M
0

Error is caused by initially set variables in constructor. If you have only one constructor, change your code to this.

@Entity
data class Site(
        val name: String,
        val url: String,
        @PrimaryKey(autoGenerate = true) val id: Long)

If you need empty constructor too, then you should do like this

@Entity
data class Site() {

  constructor(name: String, url: String): this() {
     this.name = name
     this.url = url
  }

    var name: String = "",
    var url: String = "",
    @PrimaryKey(autoGenerate = true) var id: Long = 0
}
Majors answered 14/2, 2019 at 10:26 Comment(1)
This does not work too. Gives en error saying Data class must have at least one primary constructor parameterMidway

© 2022 - 2024 — McMap. All rights reserved.