Suppose we have the following class:
data class KeyValuePair<T : Any>(
val key: String,
val value: T
)
If we reflect against the following instance of this class: KeyValuePair("color", "amber")
, the first property is of course kotlin.String
, but the second property has a type name of T. Is there a programmatic way to determine the this KProperty1
is generic? Except for hacks such as "class name does not contain dots".
You can get the type of a property using:
val props = KeyValuePair::class.declaredMemberProperties.first { it.name == "value" }
val returnType = props.returnType
This will give you back an instance of KType
that represents T
. However, there could potentially be a class T
defined somewhere and you wouldn't know if T
is the generic type or an actual class. Moreover, the generic type could have any name.
Given that the T
in the member property is the same T
defined as the generic type for the class, I think one way of answering your question would involve:
Example:
fun main() {
val classTypeParams = KeyValuePair::class.typeParameters
KeyValuePair::class.declaredMemberProperties.forEach { prop ->
val returnType = prop.returnType
println("${prop.name} -> ${returnType.classifier in classTypeParams}")
}
}
which prints:
key -> false
value -> true
Things became a bit more complex if you want to do the same for functions because:
fun <T> foo(): T
)If you want to find out the actual type of T
at runtime (e.g. that T
is actually a String
in your example), you can't do it because of type erasure – you could use reified
parameters in inline
functions, but even then I don't think you could get what T
is at runtime
EDIT:
actually you can get the runtime type of a reified
type parameter:
object Foo {
inline fun <reified T: Any> foo(obj: T) {
println(obj::class)
}
}
class MyClass
fun main() {
Foo.foo("some string") // prints kotlin.String
Foo.foo(123) // prints kotlin.Int
Foo.foo(MyClass()) // prints MyClass
}