Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android: How to make type converters (for Room) generic for all List of objects in Kotlin

I am using Room as the local database solution in my project. For every list of a certain object type I've added type converters to the project so the type convertor would look something like this:

@TypeConverter
fun convertListToString(video: List<VideoType>): String {

    val videoArray = arrayOfNulls<VideoType>(video.size)
    for (i in 0..video.size - 1) {
        videoArray[i] = video[i]
    }
    var str = ""
    val gson = Gson()
    for (i in videoArray.indices) {
        val jsonString = gson.toJson(videoArray[i])
        str = str + jsonString
        if (i < videoArray.size - 1) {
            str = str + strSeparator
        }
    }

    return str
}

@TypeConverter
fun convertStringToList(videoString: String): List<VideoType> {

    val videoArray = videoString.split(strSeparator.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
    val videos = ArrayList<VideoType>()
    val gson = Gson()
    for (i in 0 until videoArray.size - 1) {
        videos.add(gson.fromJson(videoArray[i], VideoType::class.java))
    }

    return videos
}

Problem only is that I have a whole bunch of List of different types that need to be converted, so currently I am just copying this code for every type. I would like to use generics, but so far haven't been able to figure out how to do it.

For example using something like:

@TypeConverter
inline fun <reified T> convertStringToList(string: String): List<T> {
    val objectArray = string.split(strSeparator.toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
    val objects = ArrayList<T>()
    val gson = Gson()
    for (i in 0 until objectArray.size - 1) {
        objects.add(gson.fromJson(objectArray[i], T::class.java))
    }
    return objects
}

isn't working and causes compilation error with Android Studio giving me an error telling: Type converters must be public

Anyone an idea how I can use generics for my Room TypeConverter?

like image 545
Rik van Velzen Avatar asked Oct 05 '17 11:10

Rik van Velzen


1 Answers

Will something like this won't work for templating?

abstract class Converters<T> {

    @TypeConverter
    fun mapListToString(value: List<T>): String {
        val gson = Gson()
        val type = object : TypeToken<List<T>>() {}.type
        return gson.toJson(value, type)
    }

    @TypeConverter
    fun mapStringToList(value: String): List<T> {
        val gson = Gson()
        val type = object : TypeToken<List<T>>() {}.type
        return gson.fromJson(value, type)
    }
}

// create 
class UserConverter : Converters<User>()

// usage
@TypeConverters(UserConverter::class)
abstract class TestDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}

or from the current example what if I do

@TypeConverter
fun <T> mapStringToList(inputString: String): List<T> {
    val array = inputString
        .split(strSeparator.toRegex())
        .dropLastWhile { it.isEmpty() }
        .toTypedArray()
    val result = mutableListOf<T>()
    val gson = Gson()
    // 👇 ----
    val type = object : TypeToken<List<T>>() {}.type
    // ----
    return array.fold(result) { acc, item ->
        acc.add(gson.fromJson(item, type))
        acc
    }
}
like image 99
Chetan Gupta Avatar answered Oct 13 '22 18:10

Chetan Gupta