Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android Room error: TypeConverter not recognised for List of Enums

The Room library is not recognizing a TypeConverter I created for a List of enums. However, when I change this to an ArrayList of enums it works fine. Anyone has any idea why and what can I do to make this work with List? (Using List in Kotlin is easier and I really don't wanna be converting back and forwards to ArrayList just because of this).

Here is my code:

My model:

@Entity
data class Example(@PrimaryKey val id: String?,
                   val name: String,
                   var days: List<DayOfWeek>?)

DayOfWeek is an enum:

enum class DayOfWeek {

    MONDAY,
    TUESDAY,
    WEDNESDAY,
    THURSDAY,
    FRIDAY,
    SATURDAY,
    SUNDAY;

    val value: Int
        get() = ordinal + 1


    companion object {

        private val ENUMS = DayOfWeek.values()

        fun of(dayOfWeek: Int): DayOfWeek {
            if (dayOfWeek < 1 || dayOfWeek > 7) {
                throw RuntimeException("Invalid value for DayOfWeek: " + dayOfWeek)
            }

            return ENUMS[dayOfWeek - 1]
        }

    }

}

My TypeConverter:

private const val SEPARATOR = ","

class DayOfWeekConverter {

    @TypeConverter
    fun daysOfWeekToString(daysOfWeek: List<DayOfWeek>?): String? {
        return daysOfWeek?.map { it.value }?.joinToString(separator = SEPARATOR)
    }

    @TypeConverter
    fun stringToDaysOfWeek(daysOfWeek: String?): List<DayOfWeek>? {
        return daysOfWeek?.split(SEPARATOR)?.map { DayOfWeek.of(it.toInt()) }
    }

}

And I set it in my DB class like this:

@Database(entities = arrayOf(Example::class), version = 1)
@TypeConverters(DayOfWeekConverter::class)
abstract class AppDatabase : RoomDatabase() {

    abstract fun exampleDao(): ExampleDao

}

My DAO looks like this:

@Dao
interface ExampleDao {

    @Query("SELECT * FROM example")
    fun getAll(): LiveData<List<Example>>

    @Insert(onConflict = REPLACE)
    fun save(examples: List<Example>)

}

The error I get with this code is:

error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
e: 

e:     private java.util.List<? extends com.example.DayOfWeek> days;

Like I said above, if I change the days property to ArrayList<DayOfWeek> (and make the changes to ArrayList in DayOfWeekConverter) then everything works fine. If anyone can help me figure this out and tell me how I can use List here it'd be of great help, it is driving me crazy :/.

like image 382
Franco Avatar asked Oct 17 '17 08:10

Franco


2 Answers

For some reason, Room does not like Kotlin List, but when I've replaced List with MutableList it started to work:

@Entity
data class Example(@PrimaryKey val id: String,
                   val name: String,
                   var days: MutableList<DayOfWeek>?)

class DayOfWeekConverter {
    companion object {

        @TypeConverter
        @JvmStatic
        fun daysOfWeekToString(daysOfWeek: MutableList<DayOfWeek>?): String? =
                daysOfWeek?.map { it.value }?.joinToString(separator = SEPARATOR)

        @TypeConverter
        @JvmStatic
        fun stringToDaysOfWeek(daysOfWeek: String?): MutableList<DayOfWeek>? =
                daysOfWeek?.split(SEPARATOR)?.map { DayOfWeek.of(it.toInt()) }?.toMutableList()
    }
}

This is not perfect solution, but hope you can investigate more with that.

Also you need to change @PrimaryKey to be not nullable

like image 71
Tomek Polański Avatar answered Nov 04 '22 22:11

Tomek Polański


The full signature of List in Kotlin is List<out E>(List<? extend E> in Java), it doesn't make any sense to convert such generic type. In other words, Room doesn't know if the input is a DayOfWeek or its subclass.

As for ArrayList and MutableList, their full signature is ArrayList<E> and MutableList<E> correspondingly, the input type is fixed and hence Room knows how to convert it.

like image 33
jaychang0917 Avatar answered Nov 04 '22 20:11

jaychang0917