Last active
October 13, 2017 03:07
-
-
Save fikr4n/acf929c22b0c7d5813311c60a42f56a2 to your computer and use it in GitHub Desktop.
Indirect generic superclass actual type arguments of a Java class (with Kotlin)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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