io.javalin.core.util.RouteOverviewUtil.kt Maven / Gradle / Ivy
The newest version!
/*
* Javalin - https://javalin.io
* Copyright 2017 David Åse
* Licensed under Apache 2.0: https://github.com/tipsy/javalin/blob/master/LICENSE
*/
package io.javalin.core.util
import io.javalin.Context
import io.javalin.Handler
import io.javalin.Javalin
class RouteOverviewRenderer(val app: Javalin) : Handler {
override fun handle(ctx: Context) {
ctx.html(RouteOverviewUtil.createHtmlOverview(app))
}
}
object RouteOverviewUtil {
@JvmStatic
fun createHtmlOverview(app: Javalin): String {
return """
Method
Path
Handler
Roles
${app.handlerMetaInfo.map { (httpMethod, path, handler, roles) ->
"""
$httpMethod
$path
${handler.metaInfo}
$roles
"""
}.joinToString("")}
"""
}
@JvmStatic
val Any.metaInfo: String
get() {
// this is just guesswork...
return when {
isClass -> (this as Class<*>).name + ".class"
isKotlinMethodReference -> {
val f = this.javaClass.getDeclaredField("function")
.apply { isAccessible = true }
.get(this)
f.runMethod("getOwner").runMethod("getJClass").runMethod("getName").toString() + "::" + f.runMethod("getName")
}
isKotlinAnonymousLambda -> parentClass.name + "::" + lambdaSign
isKotlinField -> parentClass.name + "." + kotlinFieldName
isJavaMethodReference -> parentClass.name + "::" + methodName
isJavaField -> parentClass.name + "." + javaFieldName
isJavaAnonymousLambda -> parentClass.name + "::" + lambdaSign
else -> implementingClassName + ".class"
}
}
}
private val Any.kotlinFieldName // this is most likely a very stupid solution
get() = this.javaClass.toString().removePrefix(this.parentClass.toString() + "$").takeWhile { it != '$' }
private val Any.javaFieldName: String?
get() = try {
parentClass.declaredFields.find { it.isAccessible = true; it.get(it) == this }?.name
} catch (ignored: Exception) { // Nothing really matters.
null
}
private val Any.methodName: String? // broken in jdk9+ since ConstantPool has been removed
get() {
// val constantPool = Class::class.java.getDeclaredMethod("getConstantPool").apply { isAccessible = true }.invoke(javaClass) as ConstantPool
// for (i in constantPool.size downTo 0) {
// try {
// val name = constantPool.getMemberRefInfoAt(i)[1]
// // Autogenerated ($), constructor, or kotlin's check (fix maybe?)
// if (name.contains("(\\$||checkParameterIsNotNull)".toRegex())) {
// continue
// } else {
// return name
// }
// } catch (ignored: Exception) {
// }
// }
return null
}
private const val lambdaSign = "??? (anonymous lambda)"
private val Any.parentClass: Class<*> get() = Class.forName(this.javaClass.name.takeWhile { it != '$' })
private val Any.implementingClassName: String? get() = this.javaClass.name
private val Any.isClass: Boolean get() = this is Class<*>
private val Any.isKotlinAnonymousLambda: Boolean get() = this.javaClass.enclosingMethod != null
private val Any.isKotlinMethodReference: Boolean get() = this.javaClass.declaredFields.any { it.name == "function" }
private val Any.isKotlinField: Boolean get() = this.javaClass.fields.any { it.name == "INSTANCE" }
private val Any.isJavaAnonymousLambda: Boolean get() = this.javaClass.isSynthetic
private val Any.isJavaMethodReference: Boolean get() = this.methodName != null
private val Any.isJavaField: Boolean get() = this.javaFieldName != null
private fun Any.runMethod(name: String): Any = this.javaClass.getMethod(name).apply { isAccessible = true }.invoke(this)
© 2015 - 2025 Weber Informatics LLC | Privacy Policy