108

I'm converting a project to Kotlin and I'm trying to make my model (which is also my entity) a data class I intend to use Moshi to convert the JSON responses from the API

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String,
    var overview: String,
    var poster_path: String,
    var backdrop_path: String,
    var release_date: String,
    var vote_average: Double,
    var isFavorite: Int
)

I can't build the app cause of 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). Cannot find setter for field.

The examples I found are not far from this

Ideas on how to solve it?

JJD
  • 50,076
  • 60
  • 203
  • 339
Leonardo Deleon
  • 2,577
  • 5
  • 15
  • 22
  • 1
    which kotlin version is this? Can you also print the full error message? Room should be able to handle that data class properly since it has only 1 constructor that receives all fields. – yigit Jun 11 '17 at 23:01
  • 2
    Make sure that the constructor parameter's name and type align with what Room expects. This could also occur with a keyword clash with Java. For instance, the Java keyword `static` is allowed in Kotlin but when it is compiled down, it looks like they replace it with another name causing the Room annotation processor to not be able to make the match with the field. – chRyNaN Jan 11 '18 at 17:33
  • Can you post your DAO also? – Vicky Jul 09 '18 at 12:32
  • You solve this, add blank constructor – Codelaby Jul 09 '18 at 16:24

34 Answers34

60

It's not a problem in your case, but for others, this error can occur if you have @Ignore params in your primary constructor, i.e. Room expects to have either:

  • parameterless constructor or
  • constructor with all fields not marked with @Ignore

for example:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String,
    @Ignore var overview: String) 

will not work. This will:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String) 
daneejela
  • 13,081
  • 7
  • 38
  • 50
44

Had a similar issue before.

First I've updated/added apply plugin: 'kotlin-kapt' to gradle.

Next, I've used it instead of annotationProcessor in gradle:

kapt "android.arch.persistence.room:compiler:1.0.0-alpha4"

Tha last thing was to create an immutable data class:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    val id : Int,
    val title: String,
    val overview: String,
    val poster_path: String,
    val backdrop_path: String,
    val release_date: String,
    val vote_average: Double,
    val isFavorite: Int
)

UPDATE:

This solution works when you have classes for the model and classes for Database in the same Android Module. If you have model classes in Android Library module and the rest of the code in your main module, Room will NOT recognize them.

Tomek Polański
  • 1,563
  • 12
  • 20
37

I had the same issue. You can move the @Ignore fields to class body. For example :

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String
){
    //here
    @Ignore var overview: String
 }
Rajat Sangrame
  • 311
  • 3
  • 18
Thilaw Fabrice
  • 662
  • 6
  • 10
29

you need to specify a secondary constructor like so:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int,
    var title: String,
    var overview: String,
    var poster_path: String,
    var backdrop_path: String,
    var release_date: String,
    var vote_average: Double,
    var isFavorite: Int
) {
    constructor() : this(0, "", "", "", "", "", 0.0, 0)
}    
evanchooly
  • 6,102
  • 1
  • 16
  • 23
  • 1
    Thanks! I had to add `constructor() ...`, `@PrimaryKey` and replace `val` with `var`. Instead of `constructor()` you can set default values like `var title: String = ""`. – CoolMind Mar 05 '21 at 16:58
26

To expand on the answers provided by @evanchooly and @daneejela, you need a secondary constructor to be able to use @Ignore parameters in your primary constructor. This is so Room still has a constructor that it can use when instantiating your object. Per your example, if we ignore one of the fields:

@Entity(tableName = "movies")
data class MovieKt(
        @PrimaryKey
        var id : Int,
        var title: String,
        var overview: String,
        var poster_path: String,
        var backdrop_path: String,
        @Ignore var release_date: String,
        @Ignore var vote_average: Double,
        @Ignore var isFavorite: Int
) {
    constructor(id: Int, title: String, overview: String, poster_path: String, backdrop_path: String)
        : this(id, title, overview, poster_path, backdrop_path, "", 0.0, 0)
    
}
Davide
  • 3,407
  • 1
  • 20
  • 22
FutureShocked
  • 779
  • 1
  • 10
  • 26
  • 3
    Shouldn't your syntax be `constructor(params) : this(params from primary constructor) { }` – Sudhir Singh Khanger Jan 30 '20 at 09:35
  • you can give defaults values on the full constructor, then, define an empty one: `constructor(): this(release_date = "", vote_average = 0.0, isFavorite=0)` will do the job. i.e, an empty consturctor which just set default values for ignored fields. – Jerry Tian Apr 04 '23 at 00:48
14

What worked for me:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int? = 0,
    var title: String? = "",
    var overview: String? = "",
    var poster_path: String? = "",
    var backdrop_path: String? = "",
    var release_date: String? = "",
    var vote_average: Double? = 0.0,
    var isFavorite: Int? = 0
)
stevenwood
  • 211
  • 1
  • 6
12

Kotlin allows long as a parameter name, but this won't work when room generates java code.

Erik B
  • 2,810
  • 1
  • 34
  • 38
12

Today I was having this problem. I used @Ignore, that is why I got the error. To solve this I created a secondary constructor. So my code looks something like this:

@Entity(tableName = "profile")
data class Profile(
  @field:SerializedName("id") @PrimaryKey @ColumnInfo(name = "id") var id:Long,
  @field:SerializedName("foo") @ColumnInfo(name = "foo") var foo:String?,
  @field:SerializedName("bar") @Ignore var Bar:String?
){
   constructor(id:Long, foo:String) : this(id, foo, null)
}

This worked for me.

Qazi Fahim Farhan
  • 2,066
  • 1
  • 14
  • 26
11

For me all I had to do was to add a constructor to the data class with empty params sent to it like so:

    @Entity(tableName = "posts")
data class JobPost(
    @Ignore
    @SerializedName("companyLogo")
    var companyLogo: String,
    @Ignore
    @SerializedName("companyName")
    var companyName: String,
    @Ignore
    @SerializedName("isAggregated")
    var isAggregated: String,
    @PrimaryKey(autoGenerate = false)
    @SerializedName("jobID")
    var jobID: String,
    @Ignore
    @SerializedName("jobTitle")
    var jobTitle: String,
    @Ignore
    @SerializedName("postedOn")
    var postedOn: String,
    @Ignore
    @SerializedName("region")
    var region: String
) {
    constructor() : this("","","","","","","")
}
Ahmed Awad
  • 1,787
  • 3
  • 16
  • 22
  • thanks, this should be the accepted answer. @Leonardo Deleon sometimes, the issue rises up, because we didn't assign a default value on the properties. ```e.g: var postedOn: String = "" // this should fix the error as well``` – mochadwi Feb 18 '19 at 02:48
  • Only answer that worked for me using @Ignore params. – novas1r1 Nov 12 '19 at 12:26
9

I also had this issue, but i realized the problem was that i added the @Embedded annotation to a property that already had a type converter, so anyone having the same problem should check the property declarations for your model class carefully and make sure the @Embedded annotation is not on a property that has a type converter associated with it.

caleb grimah
  • 183
  • 1
  • 15
9

I spent an hour trying to figure this out with no success. This is what I found. I forgot to add the return type in one of my Queries

this resulted with the POJO error

@Query("SELECT userNote FROM CardObject WHERE identifier = :identifier")
suspend fun getUserNote(identifier: String)

No POJO error

@Query("SELECT userNote FROM CardObject WHERE identifier = :identifier")
suspend fun getUserNote(identifier: String): String
seekingStillness
  • 4,833
  • 5
  • 38
  • 68
5

I think that a good option for resolve it is:

@Entity(tableName = "movies")
data class MovieKt(
    @PrimaryKey
    var id : Int = 0,
    var title: String = "",
    var overview: String = "",
    var poster_path: String = "",
    var backdrop_path: String = "",
    var release_date: String = "",
    var vote_average: Double = 0.0,
    var isFavorite: Int = 0
)
Romcel Geluz
  • 583
  • 2
  • 10
tito
  • 59
  • 3
3

For me, I was using 'lat' & 'long' as a variable name in the data(Entity) class for kotlin so renaming to latitude & longitude it worked.

Not working:

@Entity(tableName = "table_User")
data class User(@PrimaryKey var userId : Int, @ColumnInfo(name = "first_name") 
var firstName: String
            , @ColumnInfo(name = "last_name") var lastName: String
            , @ColumnInfo(name = "password") var password: String
            , @ColumnInfo(name = "dob") var dob: Long
            , @ColumnInfo(name = "address") var address: String
            , @ColumnInfo(name = "lat") var latitude: Double
            , @ColumnInfo(name = "long") var longitude: Double) {

}

Working:

@Entity(tableName = "table_User")
data class User(@PrimaryKey var userId : Int, @ColumnInfo(name = "first_name") 
var firstName: String
            , @ColumnInfo(name = "last_name") var lastName: String
            , @ColumnInfo(name = "password") var password: String
            , @ColumnInfo(name = "dob") var dob: Long
            , @ColumnInfo(name = "address") var address: String
            , @ColumnInfo(name = "latitude") var latitude: Double
            , @ColumnInfo(name = "longitude") var longitude: Double) {

}
Muhammad Maqsood
  • 1,622
  • 19
  • 25
2

I had this problem with an entity (all fields were properly-initialized vars like a lot of the answers here are suggesting) that included a list of related, non-primitive items like the OP in this SO question had. For example:

@Entity(tableName = "fruits")
data class CachedFruitEntity(
        @PrimaryKey var id: Long = 0L,
        @Embedded(prefix = "buyer_") var buyerEntity: CachedBuyerEntity? = null
        @TypeConverters(VendorsConverter::class)
        var vendorEntities: List<CachedVendorEntity?> = listOf()))

That is, it has an embedded field, and it took me a while to realize that what I actually needed was a type converter for the vendor entity list instead (the compiler wasn't throwing the usual Error:(58, 31) error: Cannot figure out how to save this field into database. You can consider adding a type converter for it. So my solution was very similar to this answer

This google architecture components github thread has more info on this misleading error, but not sure if the issue has been fixed yet.

kip2
  • 6,473
  • 4
  • 55
  • 72
2

Like it's said in the Room docs, you are required to make an empty public constructor. At the same time, if you want to declare other custom constructors, you must add @Ignore annotation.

@Entity
public class CartItem {
    @PrimaryKey
    public int product_id;
    public int qty;

    public CartItem() {
    }

    @Ignore
    public CartItem(int product_id, int count) {
        this.product_id = product_id;
        this.qty = count;
    }
}
Sreekant Shenoy
  • 1,420
  • 14
  • 23
1

It turned out to be a bug on the library https://github.com/googlesamples/android-architecture-components/issues/49

Leonardo Deleon
  • 2,577
  • 5
  • 15
  • 22
1

https://issuetracker.google.com/issues/62851733

i found this is @Relation's projection bug! not Kotlin language problem. based google GithubBrowserSample java also happend error, but different error message.

below is my kotlin code:

data class UserWithCommunities(
        @Embedded
        var user: User = User(0, null),

        @Relation(parentColumn = "id",
                entityColumn = "users_id",
                entity = CommunityUsers::class,
                projection = arrayOf("communities_id")) // delete this line.
        var communityIds: List<Int> = emptyList()
)

right:

data class UserWithCommunities(
        @Embedded
        var user: User = User(0, null),

        @Relation(parentColumn = "id",
                entityColumn = "users_id",
                entity = CommunityUsers::class)
        var communityList: List<CommunityUsers> = emptyList()
)
changhao cui
  • 469
  • 4
  • 7
1

Same bug, much stranger solution: Do not return cursor using reactivex Maybe<Cursor> on your Dao. Flowable, Single, and Observable did not work either.

Simply bite the bullet and make the reactive call outside the Dao request. Before:

@Dao
interface MyDao{
    @Query("SELECT * FROM mydao")
    fun getCursorAll(): Flowable<Cursor>
}

After:

@Dao
interface MyDao{
    @Query("SELECT * FROM mydao")
    fun getCursorAll(): Cursor
}

Meta:

Android Studio 3.2
Build #AI-181.5540.7.32.5014246, built on September 17, 2018
JRE: 1.8.0_152-release-1136-b06 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.12.6
Blaze Gawlik
  • 337
  • 3
  • 11
1

Just add the below annotation to any constructor that causes the errors and add a new blank constructor.

@Ignore

SilenceCodder
  • 2,874
  • 24
  • 28
1

With 2.1.0-alpha6, it turned out to be an invalid return type in Dao. Fixing the return type as expected fixed it.

Vairavan
  • 1,246
  • 1
  • 15
  • 19
1

Kotlin plugin doesn't pick up annotationProcessor dependencies, So use the latest version of Kotlin annotation processor - put this line at top of your module's level build.gradle file

apply plugin: 'kotlin-kapt'

like

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'  // add this line

android {
    compileSdkVersion 28
    defaultConfig {
      ........
    }
}

Don't forget to change the compileSdkVersion accordingly.

Ekeuwei
  • 273
  • 3
  • 7
1

I had the same problem and the reason was because the type of data I was getting by query in dao , was not equal to the type of data I was returning.

The type of id in my database was String and I changed the dao from:

@Query("SELECT id FROM content_table")
fun getIds(): Flow<List<Int>>

To :

@Query("SELECT id FROM content_table")
fun getIds(): Flow<List<String>>
Tomerikoo
  • 18,379
  • 16
  • 47
  • 61
1

For this issue, I had the same problem.

Replace the Room Dependencies with that of the latest one present in the official docs

Abhishek Dutt
  • 1,308
  • 7
  • 14
  • 24
Amer Biro
  • 11
  • 1
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/30092550) – Toni Oct 16 '21 at 14:24
0

As stated in Room Database Entity:

Each entity must either have a no-arg constructor or a constructor whose parameters match fields (based on type and name).

So adding an empty constructor and annotating your parameterized constructor with @Ignore will solve your problem. An example:

public class POJO {

    long id;

    String firstName;

    @Ignore
    String lastName;

    public POJO() {
    }

    @Ignore
    public POJO(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    // getters and setters
    // ...

}
Rajarshi
  • 2,419
  • 3
  • 23
  • 36
0

make sure room database column name and field name in constructor are same

Asad
  • 1,241
  • 3
  • 19
  • 32
0

In my case I had the @Ignore Tags and 'kotlin-kapt' plugin but still this started to happen after updating to kotlin to version 1.5.0.

I ended up updating my room library from version 2.2.5 to 2.3.0 and the problem was fixed.

jobernas
  • 686
  • 1
  • 12
  • 24
0

another problem with

@Entity
data class SomeEnity(
    @PrimaryKey(autoGenerate = true)
    val id: Long = 0,
    val filed: SomeClass
)

**inline** class SomeClass

consider to remove inline class

iscariot
  • 434
  • 7
  • 14
0

If u use Java. Then my solution was to only ADD @Nonull in the constructor constructor(@Nonull String,

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Mar 08 '22 at 09:46
  • The question has `kotlin` tag to mention that the OP used Kotlin for programming. – Abhishek Dutt Mar 11 '22 at 03:32
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/31236807) – Abhishek Dutt Mar 11 '22 at 03:35
0

I've been having this error for the longest time. And so I want to give tips to those who are facing the same problem, it may help you.

  1. Add all these dependencies or choose the one you will be using : https://developer.android.com/jetpack/androidx/releases/lifecycle
  2. Make sure while creating your Class (in my case Public Class Message) it implements Serializable (example)
  1. Avoid naming your attr with capital in front, it will be hard for the DAO_impl to detect. If you want to then make sure the getter and setter is also capitalized.
Ryan M
  • 18,333
  • 31
  • 67
  • 74
0

In my case I was using datatype name long as a field name

@Entity(tableName = "MyLocations") data class MyLocationModel( @PrimaryKey(autoGenerate = true) val id: Int = 0, var name: String, val stored: Boolean, val lat: Double, val long: Double )

just changed long to lon worked for me

@Entity(tableName = "MyLocations") data class MyLocationModel( @PrimaryKey(autoGenerate = true) val id: Int = 0, var name: String, val stored: Boolean, val lat: Double, val lon: Double )

  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community May 03 '22 at 20:41
0

i remove @Ignore from one of my field, then it compiled without error

@Entity(tableName = "user_table")
data class User(
    @PrimaryKey(autoGenerate = true) val id: Int,
    @ColumnInfo(name = "first_name") val firstName: String,
    @ColumnInfo(name = "last_name") val lastName: String,
    val age: Int // removed @Ignore from this field
)
-1

Don't use to dataclass,use normal class instead. This method will solve problem

Enciyo
  • 52
  • 1
  • 5
-1

In my case I wasn't returning type in one of the Dao query hope it helps others Thanks

blackHawk
  • 6,047
  • 13
  • 57
  • 100
-2

For a variation on FutureShocked answer that implements autoGenerate:

@Entity(tableName = "movies")
data class MovieKt(
        var title: String,
        var overview: String,
        var poster_path: String,
        var backdrop_path: String,
        @Ignore var release_date: String,
        @Ignore var vote_average: Double,
        @Ignore var isFavorite: Int
) {
@PrimaryKey(autoGenerate = true) var id : Int = 0

    constructor(title: String, overview: String, poster_path: String, backdrop_path: String) {
        this(id, title, overview, poster_path, backdrop_path, "", 0.0, 0)
    }
}
Samuel
  • 395
  • 2
  • 5
  • 20