I have this generic method:
class Deserializer<T : Any> : ResponseDeserializable<T> {
override fun deserialize(reader: Reader): T? {
val type = object: TypeToken<T>() {}.type
return Gson().fromJson(reader, type)
}
}
but the val type = object: TypeToken<T>() {}.type
is returning "T" to me, instead the type of the class passed.
Is there a way to get the type of the class passed as "T"?
Since the Deserializer
body is compiled only once, the compiler cannot create different classes for object : TypeToken<T>() {}
with different concrete types substituting the type parameter T
(thus it just leaves T
as it is), while this condition is essential for generics reification with TypeToken
to work.
You can only obtain the concrete type with TypeToken
where a concrete type is present in the source code or inside an inline
function with a reified
type parameter.
You can fix your code by adding a TypeToken
parameter to the constructor of Deserializer
and using an inline
factory function:
class Deserializer<T : Any>(
val typeToken: TypeToken<T>
) : ResponseDeserializable<T> {
override fun deserialize(reader: Reader): T? {
val type = typeToken.type
return Gson().fromJson(reader, type)
}
}
inline fun <reified T> deserializerOf(): Deserializer<T> =
Deserializer(object : TypeToken<T>() {})
Usage example:
val deserializer = deserializerOf<MyType>()
This will work because, when the function is inlined, the compiler transforms its body for each of its call sites, and the transformations include substituting the reified type parameters with the concrete types.