genericskotlintypetoken

Get generic type of T in Kotlin


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"?


Solution

  • 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.