如果有人可以,请解释为什么这个TypeConverter工作:
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
abstract class SetConverter <T>{
private val gson = Gson()
private val setType = object: TypeToken<Set<T>>(){}.type
@TypeConverter
fun toJson(set: Set<T>): String{
return gson.toJson(set, setType)
}
@TypeConverter
fun fromJson(json: String): Set<T>{
return gson.fromJson(json, setType)
}
}
在实体中,我通过以下实现使用SetConverter:
class CalendarSetConverter: SetConverter<Calendar>()
这很管用。
但是类的类似TypeConverter不起作用。
import androidx.room.TypeConverter
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
abstract class ClassConverter<T> {
private val gson = Gson()
private val type = object : TypeToken<T>(){}.type
@TypeConverter
fun toJson(value: T): String{
return gson.toJson(value, type)
}
@TypeConverter
open fun fromJson(json: String): T{
return gson.fromJson(json, type)
}
}
实体执行:
class CalendarConverter : ClassConverter<Calendar>()
从数据库读取日历时,此实现在运行时抛出错误:Caused by: java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to java.util.Calendar
如何为房间创建通用的TypeConverter?
1条答案
按热度按时间qaxu7uf21#
实际上,您的
CalendarSetConverter
很可能也没有按照您的预期运行,但由于类型擦除,您很可能还没有注意到这个问题。如果您尝试使用CalendarSetConverter
返回的Set
中的元素,您也会遇到ClassCastException
:这两种方法的潜在问题也是类型擦除。你永远不应该创建一个
object : TypeToken<...>
来捕获一个类型参数(例如T
),除非那个类型参数被具体化。否则在编译时使用类型参数的上限,或者Any
(如果没有明确指定上限)。所以你的代码实际上看起来是这样的:x一个一个一个一个x一个一个二个x
Gson将
Any
(分别为java.lang.Object
)反序列化为Map
,更准确地说是其内部类LinkedTreeMap
,这导致了您所遇到的ClassCastException
。这不适用于序列化(toJson
),其中Gson在序列化Any
时将使用运行时类型。要解决此问题,您必须将
TypeToken
作为构造函数参数,例如:然后创建转换器子类,如下所示:
不过我不知道这是否适用于Room,也许this question提供了更好的解决方案。