Last week, a user called " Michal Zhradnk Nono3551" asked a very interesting question on StackOverflow, which is definetly more interesting than you might think at a first glance.
In the code he posted, he has multiple inlineable functions which hold a single, reifiable type parameter. He passes them from one function to another and, after two passes, he tries to deserialize a JSON-String using Gson based on the type parameter he has passed two times.
As a result, the following exception has been thrown:
java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.xbionicsphere.x_card.entities.Token
I was already able to explain most of “the magic” happening there, including why Gson tries to cast LinkedTreeMap
, a Gson-internal type, to the user-defined type Token
. In short, Gson handled it like it was an instance of java.lang.Object
(not a subtype of it) and therefore applied its special handler to it. Thus, the type information must have been erased during compilation. You’ll find a snippet of Gson’s source code in the linked discussion.
The problem is: I am unable to explain why the generic type information has been erased. I’ve played around with different type constellations, but even with the following code snippet which includes almost every language feature/“data type” he used, I’m still unable to reproduce the issue.
fun main() {
test<ArrayList<String>>().run();
}
inline fun <reified T : Any> test() : Runnable {
var result: Runnable? = null
val job = GlobalScope.launch {
result = suspendCoroutine<Runnable> { continuation ->
val runnable = Runnable {
val deserialized: TestContainer<T> = "{\"data\": [\"abc\"]}".jsonToObject()
println(deserialized.data)
}
continuation.resumeWith(Result.success(runnable));
}
}
return runBlocking {
job.join()
return@runBlocking result!!
}
}
inline fun <reified T>String.jsonToObject() : T {
return GsonBuilder().create().fromJson(this, object : TypeToken<T>() {}.type)
}
data class TestContainer<T : Any>(val data: T)
I’ve also tested the type arguments passed to the type varialbe T
multiple times and in even more diverse constellations, the type was always correct.
You can find the original question here. I hope posting a link to a question on StackOverflow doesn’t pose a problem since I’m not allowed to copy his code either and the question doesn’t get a lot of attention on the other platform as it already has been marked as solved.
Thank you very much in advance!