在 kotlin 中,如何 return 由泛型 class 参数定义的实例

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

我正在尝试针对 kotlin 1.0.3 为 Web 框架编写一个不错的 Kotlin 包装器。因为我正在尝试将一个函数混合到请求中,以使用 jackson 通过 JSON 转换将它 return 变成一个 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 方法的通用 "class" 定义是 return 返回的值的类型。

我也试过了

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

以及将使用代码更改为

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

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

我如何让它使用由作为参数传入的 class 类型定义的泛型(非常类似于所有 spring api 在 java)?

更符合 Kotlin 惯用的方式是使用 reified type parameters:

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")
})

post 示例中的函数需要 route: (Request, Response) -> Any 参数,这是一个函数,接受请求和响应并 returning 一些非空值。

当您将 lambda 表达式用作 route 时,它的 return 类型是从 lambda 主体的最后一个表达式推断出来的,并且由于在 Kotlin 中赋值不是表达式,所以下面的 lambda根本没有 return 类型:

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

要使其工作,只需将 bean 作为最后一个表达式

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

或者根本不使用赋值:

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

注意:我使用了下面的asDataBean函数定义:

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

你也可以做一个具体化的重载,它调用非具体化的重载,这样你就不必暴露所有的内部结构:

inline fun <reified T: Any> Request.asDataBean(): T = 
    asDataBean(T::class)

req.asDataBean<TestBean>() // usage