是否可以将 Spring HATEOAS WebFluxLinkBuilders 与 Kotlin 协同程序一起使用?
Is it possible to use Spring HATEOAS WebFluxLinkBuilders with Kotlin Coroutines?
我正在尝试将以下响应式代码转换为 kotlin 协程:
@GetMapping
fun getAllTodosMono(): Mono<CollectionModel<TodoItem>> =
repository
.findAll()
.collectList()
.flatMap { mkSelfLinkMono(it) }
private fun mkSelfLinkMono(list: List<TodoItem>): Mono<CollectionModel<TodoItem>> {
val method = methodOn(Controller::class.java).getAllTodosMono()
val selfLink = linkTo(method).withSelfRel().toMono()
return selfLink.map { CollectionModel.of(list, it) }
}
协程版本:
@GetMapping
suspend fun getAllTodosCoroutine(): CollectionModel<TodoItem> =
repository
.findAll()
.collectList()
.awaitSingle()
.let { mkSelfLinkCoroutine(it) }
private suspend fun mkSelfLinkCoroutine(list: List<TodoItem>): CollectionModel<TodoItem> {
val method = methodOn(Controller::class.java).getAllTodosCoroutine()
val selfLink = linkTo(method).withSelfRel().toMono().awaitSingle()
return CollectionModel.of(list, selfLink)
}
但是,我在尝试 运行 代码时遇到 运行 时间错误。
java.lang.ClassCastException: class org.springframework.hateoas.server.core.LastInvocationAware$$EnhancerBySpringCGLIB$$d8fd0e7e cannot be cast to class org.springframework.hateoas.CollectionModel (org.springframework.hateoas.server.core.LastInvocationAware$$EnhancerBySpringCGLIB$$d8fd0e7e is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @62b177e9; org.springframework.hateoas.CollectionModel is in unnamed module of loader 'app')
我怀疑 methodOn(...) 不支持挂起函数。唯一实际可行的解决方案是手动构建 link 而不是使用 linkTo(...) 函数:
private fun mkSelfLink(list: List<TodoItem>): CollectionModel<TodoItem> {
return Link
.of("/api/v1/todos")
.withSelfRel()
.let { CollectionModel.of(list, it) }
}
但是,我失去了 link 到我的 REST 控制器中的现有端点以及自动添加到 link uri 的主机的能力。
我是不是漏掉了什么?
编辑:这是我的 github 回购的 link:https://github.com/enolive/kotlin-coroutines/tree/master/todos-coroutini
如果您将以下代码示例粘贴到 TodoController 中替换原来的 getTodo(...) 方法,您会看到我上面描述的失败。
private suspend fun Todo.withSelfLinkByBuilder(): EntityModel<Todo> {
val method = methodOn(Controller::class.java).getTodo(id!!)
val selfLink = linkTo(method).withSelfRel().toMono().awaitSingle()
return EntityModel.of(this, selfLink)
}
@GetMapping("{id}")
suspend fun getTodo(@PathVariable id: ObjectId) =
repository.findById(id)?.withSelfLinkByBuilder()
?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
您可能忘记了将协程添加到您的项目中。将这些依赖项添加到您的 gradle 文件中:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
好吧,我找到了一个解决方案,我不知道是否是一个令人满意的解决方案,但它有效,none 的较少。
通过简单地将函数调用链接在一起,运行时似乎按预期工作:
private suspend fun mkSelfLinkCoroutine(list: List<TodoItem>): CollectionModel<TodoItem> {
val selfLink = linkTo(methodOn(Controller::class.java)
.getAllTodosCoroutine())
.withSelfRel()
.toMono()
.awaitSingle()
return CollectionModel.of(list, selfLink)
}
这确实很奇怪,但事实就是如此。
我正在尝试将以下响应式代码转换为 kotlin 协程:
@GetMapping
fun getAllTodosMono(): Mono<CollectionModel<TodoItem>> =
repository
.findAll()
.collectList()
.flatMap { mkSelfLinkMono(it) }
private fun mkSelfLinkMono(list: List<TodoItem>): Mono<CollectionModel<TodoItem>> {
val method = methodOn(Controller::class.java).getAllTodosMono()
val selfLink = linkTo(method).withSelfRel().toMono()
return selfLink.map { CollectionModel.of(list, it) }
}
协程版本:
@GetMapping
suspend fun getAllTodosCoroutine(): CollectionModel<TodoItem> =
repository
.findAll()
.collectList()
.awaitSingle()
.let { mkSelfLinkCoroutine(it) }
private suspend fun mkSelfLinkCoroutine(list: List<TodoItem>): CollectionModel<TodoItem> {
val method = methodOn(Controller::class.java).getAllTodosCoroutine()
val selfLink = linkTo(method).withSelfRel().toMono().awaitSingle()
return CollectionModel.of(list, selfLink)
}
但是,我在尝试 运行 代码时遇到 运行 时间错误。
java.lang.ClassCastException: class org.springframework.hateoas.server.core.LastInvocationAware$$EnhancerBySpringCGLIB$$d8fd0e7e cannot be cast to class org.springframework.hateoas.CollectionModel (org.springframework.hateoas.server.core.LastInvocationAware$$EnhancerBySpringCGLIB$$d8fd0e7e is in unnamed module of loader org.springframework.boot.devtools.restart.classloader.RestartClassLoader @62b177e9; org.springframework.hateoas.CollectionModel is in unnamed module of loader 'app')
我怀疑 methodOn(...) 不支持挂起函数。唯一实际可行的解决方案是手动构建 link 而不是使用 linkTo(...) 函数:
private fun mkSelfLink(list: List<TodoItem>): CollectionModel<TodoItem> {
return Link
.of("/api/v1/todos")
.withSelfRel()
.let { CollectionModel.of(list, it) }
}
但是,我失去了 link 到我的 REST 控制器中的现有端点以及自动添加到 link uri 的主机的能力。
我是不是漏掉了什么?
编辑:这是我的 github 回购的 link:https://github.com/enolive/kotlin-coroutines/tree/master/todos-coroutini
如果您将以下代码示例粘贴到 TodoController 中替换原来的 getTodo(...) 方法,您会看到我上面描述的失败。
private suspend fun Todo.withSelfLinkByBuilder(): EntityModel<Todo> {
val method = methodOn(Controller::class.java).getTodo(id!!)
val selfLink = linkTo(method).withSelfRel().toMono().awaitSingle()
return EntityModel.of(this, selfLink)
}
@GetMapping("{id}")
suspend fun getTodo(@PathVariable id: ObjectId) =
repository.findById(id)?.withSelfLinkByBuilder()
?: throw ResponseStatusException(HttpStatus.NOT_FOUND)
您可能忘记了将协程添加到您的项目中。将这些依赖项添加到您的 gradle 文件中:
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
好吧,我找到了一个解决方案,我不知道是否是一个令人满意的解决方案,但它有效,none 的较少。
通过简单地将函数调用链接在一起,运行时似乎按预期工作:
private suspend fun mkSelfLinkCoroutine(list: List<TodoItem>): CollectionModel<TodoItem> {
val selfLink = linkTo(methodOn(Controller::class.java)
.getAllTodosCoroutine())
.withSelfRel()
.toMono()
.awaitSingle()
return CollectionModel.of(list, selfLink)
}
这确实很奇怪,但事实就是如此。