【问题标题】:Polymorphic @RequestBody in Spring-BootSpring-Boot 中的多态 @RequestBody
【发布时间】:2020-01-29 16:31:23
【问题描述】:

问题很简单。我有几个从同一个接口派生的事件,我想将它们反序列化为它们的propper超类。

我知道如何使用对象映射器来做到这一点,但使用我自己的映射器意味着让 Spring-Boot 将 @RequestBody 解析为字符串,然后自己进行,这不是世界末日,但我可以'不由怀疑 Spring 提供了适当的工具来处理这种情况。麻烦的是,我似乎找不到它们。

这里有一些示例代码:

示例事件:

interface YellowOpsEvent {
    val user: String
    val partner: String
    val subject: String
    val change: NatureOfChange
}

data class StatusChangedEvent(override val user: String,
                              override val partner: String,
                              override val subject: String,
                              val before: String,
                              val after: String): YellowOpsEvent {
    override val change = NatureOfChange.Changed
}

控制器:

@PostMapping("/event")
    fun writeEvent(@RequestBody event: YellowOpsEvent) {  // < I expect this not to throw an exception
        val bugme = event is StatusChangedEvent // < I expect this to return true if I send the proper event data.
    }

澄清一下,我完全理解为什么这不能开箱即用。问题是,我不知道我需要做什么才能让它工作。

【问题讨论】:

标签: spring-boot spring-mvc


【解决方案1】:

pL4Gu33 评论中的链接将我引向了正确的方向,但它需要一些额外的搜索和摆弄,从这里和那里提取信息才能得出最终可行的解决方案,所以为了完整起见,我在这里对其进行总结。

问题在于您需要两个注释,一个在接口上,一个在实现类上,组合使用 似乎有些记录不充分。 首先,在界面上,添加这个注解。与您会发现的一些教程相反,不需要对接口进行进一步注释:

@JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")
interface YellowOpsEvent {
    val user: String
    val partner: String
    val subject: String
    val change: NatureOfChange
}

根据一些文档,仅此一项就足以进行适当的反序列化。然而,spring-boot 控制器会抛出异常,因为传递的根名称与它所期望的类不匹配。

// the above will throw an exception when the serialization product is sent to this controller:

    @PostMapping("/event")
        fun writeEvent(@RequestBody event: YellowOpsEvent) {  // < I expect this not to throw an exception
            val bugme = event is StatusChangedEvent // < I expect this to return true if I send the proper event data.
        }

要解决这个问题,请将@JsonRootName 注释添加到任何实现类,并使用接口的 名称。该注释的大多数文档都没有为此使用它,而只是用于重命名类型,即使在多态性上下文中的链接问题中提到它,它也错误地使用了自己的名称。这就是它需要的样子:

@JsonRootName("YellowOpsEvent")
data class StatusChangedEvent(override val user: String,
                              override val partner: String,
                              override val subject: String,
                              val before: String,
                              val after: String): YellowOpsEvent {
    override val change = NatureOfChange.Changed
}

现在可以了! :)

【讨论】:

  • Aaa 那是你意识到使用 wrap-root-value 会破坏 swagger-ui 的时候。回到第一格...
猜你喜欢
  • 2021-02-07
  • 1970-01-01
  • 2022-01-04
  • 1970-01-01
  • 1970-01-01
  • 2019-09-11
  • 1970-01-01
  • 2018-10-07
  • 1970-01-01
相关资源
最近更新 更多