Hi guys, I'm having a problem with Room TypeConver...
# android
n
Hi guys, I'm having a problem with Room TypeConverters and Kotlin (I guess it's just a Room issue but since I'm using Kotlin for that, I consider it a Kotlin issue as well). This is the class I'd like to persist or a shorter version of it:
Copy code
@Entity
data class Customer(
@PrimaryKey
var id: Int,
var name: String,
var paymentAccounts: List<PaymentAccount>,
var addresses: List<Address> )
What we want to acheive is a generic solution for TypeConverters. This is the first not-a-100%-correct solution we came up with:
Copy code
fun <T> fromList(list: T?): String? {
list?.let {
val gson = Gson()
val type = object: TypeToken<T>(){}.type
val json = gson.toJson(list, type)
return json
} ?: run {
return null
}
}

fun <T> toList(json: String?): T? {
json?.let {
val gson = Gson()
val type = object: TypeToken<T>(){}.type
val list = gson.fromJson<T>(json, type)
return list
} ?: run {
return null
}
}
@TypeConverter
fun fromPaymentAccountList(list: List<PaymentAccount>?) = fromList(list)
@TypeConverter
fun toPaymentAccountList(json: String?) = toList<List<PaymentAccount>>(json)
@TypeConverter
fun fromAddressList(list: List<Address>?) = fromList(list)
@TypeConverter
fun toAddressList(json: String?) = toList<List<Address>>(json)
With this approach we have only one big problem: no compilation errors, no other errors BUT all the properties in the data class are converted to `LinkedTreeMap`s instead of proper objects. Our Customer class fortunately is not so complicated but we have other classes with list of objects and each object contains another list of other objects. It makes no sense to me to write a converter for each type that I want to persist with Room. Is there a solution to this problem? p.s.: we've also tried to create a generic TypeConverter method by using a reified generic with inline functions but at build time, we had multiple convertion errors
g
This code shouldn't work without reified, because you cannot create proper TypeToken without reified, generic erased on this point. What problem with reified do you have?
r
I ever had same problem. But, at that time I am using java and sqlite. The problem that was appear is coming from converter that we used in gson. I am prefer you check the type you trying to reference. This should not an issue either kotlin or room. But that gson type
n
@gildor two errors with reified:
Type converters must be public. private final <T extends java.lang.Object>java.lang.String fromList(java.util.List<? extends T> list)
and
Cannot figure out how to save this field into database. You can consider adding a type converter for it.
one for each field in the Customer object
g
Looks like you have typeadapter annotation on fromList according this error message. Could you show full code with reified
n
Copy code
@TypeConverter
    public inline fun <reified T> fromList(list: List<T>?): String? {
        list?.let {
            val gson = Gson()
            val type = object: TypeToken<List<T>>(){}.type
            val json = gson.toJson(list, type)
            return json
        } ?: run {
            return null
        }
    }

    @TypeConverter
    public inline fun <reified T> toList(json: String?): List<T>? {
        json?.let {
            val gson = Gson()
            val type = object: TypeToken<List<T>>(){}.type
            val list = gson.fromJson<List<T>>(json, type)
            return list
        } ?: run {
            return null
        }
    }
you think it's not possible to put the annotation on the fun with reified?
g
Of cours e. You need proxy method, like in you previous code snippet. Reified method works only when call site inlined, but room call it from Java. So just add reified to toList fromList of you original code (first message of this thread)
To make it completely universal Room should have API that passes TypeToken to your type adapter, without that you need typeadapter for each type of list, but actually probably it's not so bad, at least explicit solution
d
Just a side point, you could always use Kotson, it makes working w/ Gson in Kotlin a bit easier...