Skip to content

Instantly share code, notes, and snippets.

@udalov
Last active March 16, 2021 21:54
Show Gist options
  • Save udalov/bb6f398c2e643ee69586356fdd67e9b1 to your computer and use it in GitHub Desktop.
Save udalov/bb6f398c2e643ee69586356fdd67e9b1 to your computer and use it in GitHub Desktop.
DEPRECATED example how to obtain KType instance from reified T. Please use "typeOf" since 1.3.40!
import java.lang.reflect.*
import kotlin.reflect.KClass
import kotlin.reflect.KType
import kotlin.reflect.KTypeProjection
import kotlin.reflect.KVariance
import kotlin.reflect.full.createType
// --- Interface ---
inline fun <reified T : Any> getKType(): KType =
object : SuperTypeTokenHolder<T>() {}.getKTypeImpl()
// --- Implementation ---
@Suppress("unused")
open class SuperTypeTokenHolder<T>
fun SuperTypeTokenHolder<*>.getKTypeImpl(): KType =
javaClass.genericSuperclass.toKType().arguments.single().type!!
fun KClass<*>.toInvariantFlexibleProjection(arguments: List<KTypeProjection> = emptyList()): KTypeProjection {
// TODO: there should be an API in kotlin-reflect which creates KType instances corresponding to flexible types
// Currently we always produce a non-null type, which is obviously wrong
val args = if (java.isArray()) listOf(java.componentType.kotlin.toInvariantFlexibleProjection()) else arguments
return KTypeProjection.invariant(createType(args, nullable = false))
}
fun Type.toKTypeProjection(): KTypeProjection = when (this) {
is Class<*> -> this.kotlin.toInvariantFlexibleProjection()
is ParameterizedType -> {
val erasure = (rawType as Class<*>).kotlin
erasure.toInvariantFlexibleProjection((erasure.typeParameters.zip(actualTypeArguments).map { (parameter, argument) ->
val projection = argument.toKTypeProjection()
projection.takeIf {
// Get rid of use-site projections on arguments, where the corresponding parameters already have a declaration-site projection
parameter.variance == KVariance.INVARIANT || parameter.variance != projection.variance
} ?: KTypeProjection.invariant(projection.type!!)
}))
}
is WildcardType -> when {
lowerBounds.isNotEmpty() -> KTypeProjection.contravariant(lowerBounds.single().toKType())
upperBounds.isNotEmpty() -> KTypeProjection.covariant(upperBounds.single().toKType())
// This looks impossible to obtain through Java reflection API, but someone may construct and pass such an instance here anyway
else -> KTypeProjection.STAR
}
is GenericArrayType -> Array<Any>::class.toInvariantFlexibleProjection(listOf(genericComponentType.toKTypeProjection()))
is TypeVariable<*> -> TODO() // TODO
else -> throw IllegalArgumentException("Unsupported type: $this")
}
fun Type.toKType(): KType = toKTypeProjection().type!!
// --- Usage example ---
fun main(args: Array<String>) {
println(getKType<List<Map<String, Array<Double>>>>())
println(getKType<List<*>>())
println(getKType<Array<*>>())
println(getKType<Array<Array<String>>>())
println(getKType<Unit>())
}
@hinls1007
Copy link

@udalov Hello, is this kt file possible to include in my library project?

@JLLeitschuh
Copy link

@udalov Can you mention what license you've released this under so that it can be included in third party projects? Apache 2.0?

@udalov
Copy link
Author

udalov commented Jul 10, 2018

@hinls1007 @JLLeitschuh This code is licensed under WTFPL Version 2.

@ericntd
Copy link

ericntd commented Mar 16, 2021

createType doesn't seem to exist anymore

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment