I'm trying to write a nice Kotlin wrapper for a web framework against kotlin 1.0.3. In that I am trying to mixin a function to the request to have it return a bean via a JSON transformation using jackson.
So in my library I have the following
private val mapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule())
fun <T : Any> Request.asDataBean(type: KClass<T>): T = mapper.readValue(this.body(), type.java)
But when I goto use the code as such
post("/hello", { req, res ->
val bean = req.asDataBean(TestBean::class)
})
It errors saying that the expected value of bean is Any. What I want is for my API to work as above where whatever the generic "class" definition that is passed into asDataBean method is the type of value that is returned back.
I've also tried
fun <T> Request.asDataBean(type: KClass<*>): T = mapper.readValue(this.body(), type.java) as T
as well as changing the usage code to
val bean: TestBean = req.asDataBean(TestBean::class)
in hopes of making it work but they also give the exact same error when using the code.
How do I get it to use the generic defined by the class type passed in as the parameter (very similar to how all the spring api's work in java)?
Yes, this is nice especially if the generic class is abstract, you can do this in the concrete subclasses :) @TimKuipers The <E> in class Foo<E> is not bound to any particular type.
There are no direct ways to do this in Kotlin. In order to check the generic type, we need to create an instance of the generic class<T> and then we can compare the same with our class.
Kotlin generic example When we call the generic method <T>printValue(list: ArrayList<T>) using printValue(stringList), the type T of method <T>printValue(list: ArrayList<T>)will be replaced by String type.
We can make generic variable using this kind of syntax: "val destinationActivity: Class<*>". Main part is "*".
post
function in your example requires route: (Request, Response) -> Any
parameter, that is a function, taking request and response and returning some non-null value.
When you use a lambda expression as a route
, its return type is inferred from the last expression of lambda's body, and since in Kotlin an assignment is not an expression, the following lambda doesn't have the return type at all:
{ req, res ->
val bean = req.asDataBean(TestBean::class)
}
To make it work just make bean
the last expression
{ req, res ->
val bean = req.asDataBean(TestBean::class)
bean
}
or do not use the assignment at all:
{ req, res -> req.asDataBean(TestBean::class) }
Note: I have used the following definition of asDataBean
function:
fun <T: Any> Request.asDataBean(type: KClass<T>): T =
mapper.readValue(this.body(), type.java)
Also you could make a reified overload, which calls non-reified one, so that you don't have to expose all the internals:
inline fun <reified T: Any> Request.asDataBean(): T =
asDataBean(T::class)
req.asDataBean<TestBean>() // usage
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With