在kotlin中,如何返回由泛型类参数

时间:2016-07-11 05:36:47

标签: generics kotlin kotlin-extension

我正在尝试为针对kotlin 1.0.3的Web框架编写一个很好的Kotlin包装器。在那里我试图将一个函数混合到请求中,让它通过使用jackson的JSON转换返回一个bean。

所以在我的图书馆中我有以下

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

但是当我转到使用代码时

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

错误说bean的期望值是Any。我想要的是我的API如上所述,无论传递给asDataBean方法的通用“类”定义是返回的值的类型。

我也试过

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

以及将使用代码更改为

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

希望使其正常工作,但在使用代码时也会给出完全相同的错误。

如何使用传入的类类型定义的泛型作为参数(非常类似于所有spring api在java中的工作方式)?

2 个答案:

答案 0 :(得分:5)

使用reified type parameters时,Kotlin惯用法的方式越多:

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

然后可以将其用作:

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

答案 1 :(得分:4)

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