v79
01/18/2023, 7:55 PMreflect()
on a lambda specified using the ::methodName
syntax, and that it will return null? I'm experimenting with a library (https://github.com/moia-oss/lambda-kotlin-request-router) and this code passes:
POST("/something") { req: Request<Unit> -> ResponseEntity.ok(Unit) }
But this code fails, and indeed the library seems to suggest that it will always fail because of a limitation in kotlin reflection on lambdas:
val dummy = object {
fun handler(r: Request<Unit>) = ResponseEntity.ok(Unit)
}
GET("/some", dummy::handler)
The library uses kotlin reflection while processing the GET() function:
al requestType = handler.reflect()?.parameters?.first()?.type?.arguments?.first()?.type
?: throw IllegalArgumentException("reflection failed, try using a real lambda instead of function references (Kotlin 1.6 bug?)")
Clearly the library has chosen not to support the ::method syntax, despite using it in its documentation and samples. Any suggestions? Using Kotlin 1.7.22println("Handler: $handler")
Just before the call to reflect(), for the working `{ req: Request -> Response() }`syntax I get:
Handler: (io.moia.router.Request<kotlin.String>) -> io.moia.router.ResponseEntity<kotlin.String>
And for the non-working class::method
I get:
Handler: fun io.moia.router.RequestHandlerTest.DummyController.handler(io.moia.router.Request<kotlin.Unit>): io.moia.router.ResponseEntity<kotlin.String>
val requestType: KType? = try {
val fk = handler as KFunction<*>
fk.parameters.first().type.arguments.first().type
} catch (cce: ClassCastException) {
log.warn("Unable to to cast handler to KFunction; assuming it's a lambda and reflecting on that")
handler.reflect()?.parameters?.first()?.type?.arguments?.first()?.type
}
udalov
01/19/2023, 11:35 AMval kFunction = when (handler) {
is KFunction<*> -> handler
is kotlin.jvm.internal.Lambda<*> -> handler.reflect() ?: error(...)
else -> error(...)
}
val requestType = kFunction.parameters.first().type.arguments.first().type
It uses internal API though, kotlin.jvm.internal.Lambda
is the class which we use for lambdas with metadatareflect()
won’t work on them (it’s an experimental API anyway). You’ll need to mark lambdas that you need to reflect on with @JvmSerializableLambda
v79
01/19/2023, 11:44 AMval requestType: KType? = try {
val fk = handler as KFunction<*>
fk.parameters.first().type.arguments.first().type
} catch (cce: ClassCastException) {
log.warn("Unable to to cast handler to KFunction; assuming it's a lambda and reflecting on that")
handler.reflect()?.parameters?.first()?.type?.arguments?.first()?.type
}
But I guess doing the type check is better than cast-and-catch.