6

我正在尝试为针对 kotlin 1.0.3 的 Web 框架编写一个不错的 Kotlin 包装器。在那我试图将一个函数混合到请求中,让它通过使用杰克逊的 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 中的工作方式)?

4

2 回答 2

5

更 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")
})
于 2016-07-11T05:45:00.790 回答
5

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

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

{ 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
于 2016-07-11T20:52:30.273 回答