Solution 1 :
The problem is that for your decodeFunctionReturnValue
function the type parameter T
is not reified
. Therefore at runtime the TypeToken
you are creating is actually TypeToken<JsonFunctionReturnValueData<Object>>
. When deserializing Object
, Gson creates based on the JSON data standard objects, for a JSON object that is a Java Map
(and Gson’s internal implementation is LinkedTreeMap
).
So if possible the solution would be to make the type parameter T
here reified
as well. If that is not possible, maybe the type can be passed as separate TypeToken
parameter to the function.
As side note: It was already suggested that Gson should throw an exception when a TypeToken
capturing a type variable is created (which would have informed you about the problem with your code). However, due to backward compatibility concerns this was not implemented yet.
Problem :
I have a problem that appear be simple, but im making something wrong.
How i can convert from a generic class with reified using GSON and Kotlin in my project called XPLPC?
The error is here:
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)
It don’t understand that i want convert to Todo class instead of LinkedTreeMap.
The code is here:
https://github.com/xplpc/xplpc/blob/main/kotlin/lib/library/src/main/java/com/xplpc/serializer/JsonSerializer.kt#L66-L79
And the code is called by this function:
https://github.com/xplpc/xplpc/blob/main/kotlin/lib/library/src/main/java/com/xplpc/client/RemoteClient.kt#L14-L27
Basically the code is:
// 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 {
[email protected] 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
}
Comments
Comment posted by Paulo Coutinho
Nice. It can be reified because JsonSerializer inherit from an interface, and interface cant have reified. How i can pass TypeToken as parameter, since JsonFunctionReturnValueData is a class available only for JsonSerializer. Basically, how to make JsonFunctionReturnValueData works with generic and Type?
Comment posted by TypeToken.getParameterized
@PauloCoutinho, if
Comment posted by github.com/xplpc/xplpc/blob/main/kotlin/lib/library/src/main/…
Thanks. It works. Can you check if it is correct or can be problematic in future? Only a review:
Comment posted by Marcono1234
@PauloCoutinho, I only had a short look at it, but to me that looks good.