Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin reified generics does not keep the type as planned

I am creating a TypeToken-like system similar to what Gson has and I have stumbled upon something I do not understand.

The intention with this code would be to have only one TypeReference class with one generic argument that could hold multiple ones. The class would be created using inline function, this way the user does not need to know of the Holder class.

Please consider the code below:

package testing

import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

abstract class TypeReference<T : Holder> {
    val type: Type = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0]

    override fun toString(): String {
        return type.typeName
    }
}

inline fun <reified T : Holder> create() = object : TypeReference<T>() {}

inline fun <reified WHAT> createSingle() = object : TypeReference<Single<WHAT>>() {}

class Foo

interface Holder

interface Single<T> : Holder

fun main(args: Array<String>) {
    println(create<Single<HashMap<Int, String>>>())
    println(create<Single<Foo>>())

    println(createSingle<HashMap<Int, String>>())
    println(createSingle<Foo>())
}

This is the output:

testing.Single<java.util.HashMap<java.lang.Integer, java.lang.String>>
testing.Single<testing.Foo>
testing.Single<WHAT>
testing.Single<WHAT>

It looks like to me as if the Single<WHAT> (sry for that generic name) does not get 'truly' inlined and some intermediate name gets generated.

I have also looked in the docs but I did not find examples regarding this.

How can I create what I initially intended to do? Why does this happen?

Edit.:

I wanted to create an issue, but they already know about this.

A very similar issue is issued here which is said to be a duplicated of this. You can also vote in the latter link.

For future reference: Kotlin 1.2.50 is used here.

like image 881
andras Avatar asked Jun 14 '18 05:06

andras


1 Answers

I decompile this code,found some different between two func

private static final TypeReference create() {
  Intrinsics.needClassReification();                 <---- here
  return (TypeReference)(new TypeReference() {
  });
}

private static final TypeReference createSingle() {
  return (TypeReference)(new TypeReference() {
  });
}

And manual add this code, work fine. Don't known too much about this, no document found.

inline fun <reified WHAT > createSingle() = Intrinsics.needClassReification().let {
    object : TypeReference<Single<WHAT>>() {}
}

result:

Single<java.util.HashMap<java.lang.Integer, java.lang.String>>

Single<Foo>

Single<java.util.HashMap<java.lang.Integer, java.lang.String>>

Single<Foo>
like image 171
user4097210 Avatar answered Sep 21 '22 19:09

user4097210