1

I have a val built like this

val qs = hashMapOf<KProperty1<ProfileModel.PersonalInfo, *> ,Question>()

How can I obtain the class of ProfileModel.PersonalInfo from this variable?

In other words what expression(involving qs of course) should replace Any so that this test passes.

@Test
fun obtaionResultTypeFromQuestionList(){
    val resultType = Any()
    assertEquals(ProfileModel.PersonalInfo::class, resultType)
}

Thank you for your attention

1 Answer 1

4

There is no straight way to get such information due to Java type erasure. To be short - all information about generics (in your case) is unavailable at runtime and HashMap<String, String> becomes HashMap.

But if you do some changes on JVM-level, like defining new class, information about actual type parameters is kept. It gives you ability to do some hacks like this:

val toResolve = object : HashMap<KProperty1<ProfileModel.PersonalInfo, *> ,Question>() {
    init {
        //fill your data here
    }
}

val parameterized = toResolve::class.java.genericSuperclass as ParameterizedType
val property = parameterized.actualTypeArguments[0] as ParameterizedType
print(property.actualTypeArguments[0])

prints ProfileModel.PersonalInfo.

Explanation:

  1. We define new anonymous class which impacts JVM-level, not only runtime, so info about generic is left
  2. We get generic supperclass of our new anonymous class instance what results in HashMap< ... , ... >
  3. We get first type which is passed to HashMap generic brackets. It gives us KProperty1< ... , ... >
  4. Do previous step with KProperty1

Kotlin is tied to the JVM type erasure as well as Java does. You can do a code a bit nice by moving creation of hash map to separate function:

inline fun <reified K, reified V> genericHashMapOf(
        vararg pairs: Pair<K, V>
): HashMap<K, V> = object : HashMap<K, V>() {
    init {
        putAll(pairs)
    }
}

...

val hashMap = genericHashMapOf(something to something)
Sign up to request clarification or add additional context in comments.

3 Comments

yeah that works. Thanks! doesn't kotlin offer a simpler way?
Unfortunately, the coastline is tied the same as Java to type erasure, so basically no way to retrieve generics without some voodoo. I've put some improvements to the answer, maybe it will be helpful.
yeah that makes sense. Thanks

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.