在 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
我正在尝试针对 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