我有一个问题,看起来很简单,但我做错了什么。
如何在我的项目XPLPC中使用GSON和Kotlin从一个带有物化的泛型类进行转换?
错误在这里:https://github.com/xplpc/xplpc/actions/runs/3395808126/jobs/5646151499#step:9:503
com.xplpc.library.TodoTest > singleItem[test(AVD) - 12] FAILED
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.xplpc.library.TodoTest$Todo
at com.xplpc.library.TodoTest.singleItem(TodoTest.kt:44)
它不理解我想要转换为Todo类而不是LinkedTreeMap。
代码如下:https://github.com/xplpc/xplpc/blob/main/kotlin/lib/library/src/main/java/com/xplpc/serializer/JsonSerializer.kt#L66-L79
代码由以下函数调用:https://github.com/xplpc/xplpc/blob/main/kotlin/lib/library/src/main/java/com/xplpc/client/RemoteClient.kt#L14-L27
基本代码是:
// Part 1
object RemoteClient {
inline fun <reified T> call(request: Request, defValue: T? = null): T? {
try {
val data = PlatformProxy.call(request.data)
println(data)
return XPLPC.config.serializer.decodeFunctionReturnValue<T>(data)
} catch (e: Exception) {
Log.e(
Constants.LOG_GROUP,
"[RemoteClient : call] Error when try to decode return value: ${e.message}"
)
}
return defValue
}
inline fun <reified T> callAsync(request: Request, defValue: T? = null): Deferred<T?> {
return CoroutineScope(Dispatchers.IO).async {
return@async call<T>(request, defValue)
}
}
}
// Part 2
override fun <T> decodeFunctionReturnValue(data: String): T? {
try {
val type = object : TypeToken<JsonFunctionReturnValueData<T>>() {}.type
val gson = createGson()
return gson.fromJson<JsonFunctionReturnValueData<T>>(data, type).r
} catch (e: Exception) {
Log.e(
Constants.LOG_GROUP,
"[JsonSerializer : decodeFunctionReturnValue] Error when parse json: ${e.message}"
)
}
return null
}
1条答案
按热度按时间wi3ka0sx1#
问题是对于
decodeFunctionReturnValue
函数,类型参数T
不是reified
。因此在运行时,您创建的TypeToken
实际上是TypeToken<JsonFunctionReturnValueData<**Object**>>
。在反序列化Object
时,Gson基于JSON数据标准对象创建JSON对象,该对象是JavaMap
(Gson的内部实现是LinkedTreeMap
)。因此,如果可能的话,解决方案是使类型参数
T
也在这里reified
。如果不可能,也许该类型可以作为单独的TypeToken
参数传递给函数。旁注:当创建捕获类型变量的
TypeToken
时,Gson应该抛出异常的是already suggested(这将通知您代码的问题)。但是,由于向后兼容性问题,这还没有实现。