In kotlin, how to return an instance defined by the generic class parameter

I am trying to write a good Kotlin wrapper for a web framework against kotlin 1.0.3. In this, I am trying to connect a function to the request so that it returns a bean via JSON conversion using jackson.

So in my library I have

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 use the code as such

 post("/hello", { req, res -> val bean = req.asDataBean(TestBean::class) }) 

Errors indicate that the expected value of the bean is Any. I want my API to work as described above, no matter what general class definition that is passed to the asDataBean method is the type of the return value.

I also tried

 fun <T> Request.asDataBean(type: KClass<*>): T = mapper.readValue(this.body(), type.java) as T 

as well as change the usage code to

 val bean: TestBean = req.asDataBean(TestBean::class) 

hoping to make it work, but they also give the same error when using the code.

How do I get it to use the generic type defined by the type of the class passed as a parameter (very similar to how all spring api works in java)?

+5
source share
2 answers

post function in your example requires the route: (Request, Response) -> Any parameter route: (Request, Response) -> Any , which is a function that accepts a request and response and returns some non-zero value.

When you use a lambda expression as route , its return type is inferred from the last lambda body expression, and since in Kotlin an assignment is not an expression, the following lambda does not have a return type in all:

 { req, res -> val bean = req.asDataBean(TestBean::class) } 

To make it work, just make the bean last expression

 { req, res -> val bean = req.asDataBean(TestBean::class) bean } 

or not use the assignment at all:

 { req, res -> req.asDataBean(TestBean::class) } 

Note. I used the following asDataBean function asDataBean :

 fun <T: Any> Request.asDataBean(type: KClass<T>): T = mapper.readValue(this.body(), type.java) 

You can also do a reified reboot, which causes an unoriented one, so you do not need to expose all internal elements:

 inline fun <reified T: Any> Request.asDataBean(): T = asDataBean(T::class) req.asDataBean<TestBean>() // usage 
+4
source

The larger Kotlin's idiomatic way would be to use reified type parameters :

 inline fun <reified T : Any> Request.asDataBean(): T = mapper.readValue(this.body(), T::class.java) 

which can then be used as:

 post("/hello", { req, res -> val bean = req.bodyAs<TestBean>() res.body("Ok") }) 
+5
source

All Articles