Skip to content

Instantly share code, notes, and snippets.

@fikr4n
Last active October 13, 2017 03:07
Show Gist options
  • Save fikr4n/acf929c22b0c7d5813311c60a42f56a2 to your computer and use it in GitHub Desktop.
Save fikr4n/acf929c22b0c7d5813311c60a42f56a2 to your computer and use it in GitHub Desktop.
Indirect generic superclass actual type arguments of a Java class (with Kotlin)
#!/usr/bin/env kotlinc -script
import java.lang.reflect.*
import kotlin.reflect.*
fun targ(c: Class<*>) = c.typeParameters.toList()
fun satarg(c: Class<*>) = (c.genericSuperclass as? ParameterizedType)?.
actualTypeArguments?.toList() ?: emptyList()
fun isatarg(c: Class<*>?, ancestor: Class<*>, resolvedT: List<Type>): List<Type>? {
if (c == null) return null
if (c == ancestor) return resolvedT
val t = targ(c)
val sat = satarg(c).toMutableList()
print("- ${c.simpleName}${t.simpleNames} : " +
"${c.superclass?.simpleName}${sat.simpleNames} ==> ")
for (i in sat.indices) {
val pos = t.indexOf(sat[i])
if (pos >= 0) sat[i] = resolvedT[pos]
}
println("${sat.simpleNames}")
// TODO: interfaces
return isatarg(c.superclass, ancestor, sat)
}
fun isatarg(c: Class<*>, ancestor: Class<*>): List<Type>? {
return isatarg(c, ancestor, targ(c))
}
// public
fun getActualTypeArguments(implementation: KClass<*>,
indirectSuperclass: KClass<*>) =
isatarg(implementation.java, indirectSuperclass.java)
val Type.simpleName: String
get() = when (this) {
is Class<*> -> getSimpleName()
is ParameterizedType ->
"${rawType.simpleName}${actualTypeArguments.simpleNames}"
else -> toString()
}
val List<Type>.simpleNames
get() = map { it.simpleName }.joinToString(", ", "<", ">")
val Array<Type>.simpleNames
get() = asList().simpleNames
fun test(c: KClass<*>, s: KClass<*>) {
println("Actual type arguments of ${s.simpleName} from ${c.simpleName}:")
println("= ${getActualTypeArguments(c, s)}\n")
}
open class Haha<T, U>
open class Hihi<T> : Haha<T, String>()
open class Hihihi<E> : Haha<E, String>()
open class Hehe : Hihi<List<*>>()
open class Hehehe<T, U : Number> : Hihihi<U>()
open class Hohoho : Hehehe<Boolean, Byte>()
test(Haha::class, Haha::class)
test(Hihi::class, Haha::class)
test(Hehe::class, Haha::class)
test(Hehe::class, Hihi::class)
test(Hihihi::class, Haha::class)
test(Hehehe::class, Haha::class)
test(Hohoho::class, Haha::class)
test(Haha::class, Hehe::class)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment