【问题标题】:Is it possible to use Spring HATEOAS WebFluxLinkBuilders with Kotlin Coroutines?是否可以将 Spring HATEOAS WebFluxLinkBuilders 与 Kotlin 协程一起使用?
【发布时间】:2020-11-16 21:14:28
【问题描述】:

我正在尝试将以下响应式代码转换为 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: 类 org.springframework.hateoas.server.core.LastInvocationAware$$EnhancerBySpringCGLIB$$d8fd0e7e 不能转换为类 org.springframework.hateoas.CollectionModel (org.springframework.hateoas.server.core. LastInvocationAware$$EnhancerBySpringCGLIB$$d8fd0e7e 位于加载器 org.springframework.boot.devtools.restart.classloader.RestartClassLoader @62b177e9 的未命名模块中;org.springframework.hateoas.CollectionModel 位于加载器“app”的未命名模块中)

我怀疑 methodOn(...) 不支持挂起功能。唯一可行的解​​决方案是手动构建链接,而不是使用 linkTo(...) 函数:

  private fun mkSelfLink(list: List<TodoItem>): CollectionModel<TodoItem> {
    return Link
      .of("/api/v1/todos")
      .withSelfRel()
      .let { CollectionModel.of(list, it) }
  }

但是,我无法链接到 REST 控制器中的现有端点以及自动添加到链接 uri 的主机。

我错过了什么吗?

编辑:这是我的 github 存储库的链接: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)

【问题讨论】:

    标签: spring kotlin spring-hateoas


    【解决方案1】:

    好吧,我找到了一个解决方案,我不知道它是否令人满意,但它确实有效。

    通过简单地将函数调用链接在一起,运行时似乎可以按预期工作:

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

    这真的很奇怪,但它就是这样。

    【讨论】:

    【解决方案2】:

    您可能忘记将协程添加到您的项目中。将这些依赖项添加到您的 gradle 文件中:

    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core")
    implementation("org.jetbrains.kotlinx:kotlinx-coroutines-reactor")
    

    【讨论】:

    • 我检查了我的依赖项,coroutines-reactor 和 core 都是依赖项列表的一部分。我更新了我的原始问题,因此有一个指向我的 github 存储库的链接,其中包含一些演示代码(例如将上面的代码粘贴到控制器中并看到它失败)。
    猜你喜欢
    • 2018-09-05
    • 1970-01-01
    • 2022-11-23
    • 2021-01-24
    • 1970-01-01
    • 2020-10-02
    • 2021-01-16
    • 1970-01-01
    • 2020-04-10
    相关资源
    最近更新 更多