REST如何实现多态POST端点:抽象类型需要映射到具体的JSON类型

2024-03-19

我从事 SpringBoot 应用程序的工作。

我有以下类层次结构:

public abstract class DlqMessage {
    Long id;
    UUID employeeId;
    EventReason reason;
}

public class ContractUpdateMessage extends DlqMessage {}

public class SingleContractUpdateMessage extends DlqMessage {
    UUID benefitId;
    UUID employerId;
}

所以,班级ContractUpdateMessage and SingleContractUpdateMessage仅在几个字段上有所不同。

我有一个 REST 控制器,它使用 POST 在数据库中创建和保存新实体:

@PostMapping("/messages")
public ResponseEntity<DlqMessage> create(@RequestBody DlqMessage contractUpdateMessage) {
    DlqMesssage dlqEntry = dlqEntityService.save(contractUpdateMessage);
    return ResponseEntity.ok(dlqEntry);
}

现在,我有一个随机生成一个或另一个类的实例的测试:

 DlqMessage message = randomOneOf(contractUpdateMessageBuilder().build(), singleContractUpdateMessageBuilder().build());

然后我有一个测试帮助程序类,它使用 RestTemplate 向控制器发送 POST 请求:

ResponseEntity<DlqMesssage> response =
                crudRestClient.post("/messages/contract", message, DlqMesssage.class, null);
        return response.getBody();

并调用整个事情我最终得到以下例外:

Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Can not construct instance of com.orbitbenefits.benefitsselection.server.errorrecovery.entity.DlqMessage: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.orbitbenefits.benefitsselection.server.errorrecovery.entity.DlqMessage: abstract types either need to be mapped to concrete types, have custom deserializer, or contain additional type information

看起来 RestTemplate 甚至没有发送我的请求。

顺便说一句,当我为每个单独的子类型分割端点时,这一切都有效:

@PostMapping("/messages/contract")
public ResponseEntity<DlqMessage> create(@RequestBody ContractUpdateMessage contractUpdateMessage) {
    ContractUpdateMessage dlqEntry = (ContractUpdateMessage) dlqEntityService.save(contractUpdateMessage);
    return ResponseEntity.ok(dlqEntry);
}

@PostMapping("/messages/single")
public ResponseEntity<DlqMessage> create(@RequestBody SingleContractUpdateMessage contractUpdateMessage) {
    SingleContractUpdateMessage dlqEntry = (SingleContractUpdateMessage) dlqEntityService.save(contractUpdateMessage);
    return ResponseEntity.ok(dlqEntry);
}

然而,这看起来很难看,而且不是一个“正确”的解决方案。

基本上,我想知道是否可能以及如何实现以多态实例作为参数的 REST 端点以及如何调用这样的端点?


不能使用抽象类型 DlqMessage 的原因是因为您可能会收到如下消息:

{
  "id":300, 
  "employeeId":"d6a00fb2-058c-4bf7-9a0a-7cc538cd85f5"
}

Jackson 无法确定此消息打算映射的具体对象的类型。处理这个问题最简单的方法是定义一个类型提示,例如:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "messageType")
@JsonSubTypes({
    @JsonSubTypes.Type(value=ContractUpdateMessage.class, name = "ContractUpdateMessage"),
    @JsonSubTypes.Type(value=SingleContractUpdateMessage.class, name = "SingleContractUpdateMessage")
})
public abstract class DlqMessage { ... }

这样,下次进行 API 调用时,您还必须在 JSON 对象中包含此类型提示:

{
  "id":300, 
  "employeeId":"d6a00fb2-058c-4bf7-9a0a-7cc538cd85f5",
  "messageType":"ContractUpdateMessage"
}

这样,Jackson 的默认对象映射器将使用“messageType”字段来猜测您的 API 正在接收哪种类型的 DlqMessage。

编辑:您可以在此处找到更多信息:

https://www.baeldung.com/jackson-annotations https://www.baeldung.com/jackson-annotations

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

REST如何实现多态POST端点:抽象类型需要映射到具体的JSON类型 的相关文章

随机推荐

  • 包含第一个元素的反转数组切片[重复]

    这个问题在这里已经有答案了 假设我有 gt gt gt a 1 2 3 4 我想要一个反转的切片 假设我想要给出第 1 个和第 0 个元素start idx 1 and stop idx 0 2 1 使用切片符号 a x y z 我用什么值
  • 音乐播放列表数据库设计

    如何构建歌曲和播放列表的表格 我的想法是创建一个播放列表标题和 id 的表 然后创建一个播放列表歌曲表 其中保存歌曲的唯一 id 及其所属的播放列表 另一个为每个播放列表规划一个新表 并将播放列表的歌曲信息存储在每个表中 这是一个好方法还是
  • GenyMotion 无法启动 Genymotion 虚拟设备

    当我运行 Genymotion 时 出现以下错误 无法启动 Genymotion 虚拟设备 无法为虚拟设备配置网络适配器 请检查以下几点 在 VirtualBox 中 在软件的主要参数中 检查是否存在 Host only 网络适配器 在 V
  • C 字符值算术

    我一直在阅读 C 编程语言 一书来学习 C 我偶然发现了算术s i 0 他们说它给出了存储在 s i 中的字符的数值 我不太明白 它怎么能通过减法给出值呢 注意 这用在 atoi 函数中 该函数将数字字符串转换为其等价的数字 谢谢 可能重复
  • 如何通过命令行关闭Android模拟器

    我无法从命令提示符正常停止模拟器 我使用的是 Linux Ubuntu v10 04 64 位 和 Android v2 3 API 9 Gingerbread 我使用其快照启动了模拟器 现在我关心的是优雅地关闭正在运行的模拟器实例 我尝试
  • 手机应用程序设计指南[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有包含创建移动电话应用程序的设计指南的文档或文章 如何构建应用程序以获得理想的用户体验 用户界面和键
  • 通过API重置登录cookie

    我想知道是否有任何方法可以通过API重置登录cookie 我知道如何通过管理中的设置来做到这一点 切换changePasswordAtNextLoginG Suite 用户的标记将其从所有设备中注销 使changePasswordAtNex
  • 如何使用 JsTestDriver 测试 jquery 和 ajax 调用?

    我有一个用 jQuery 构建的动态页面 Html 片段加载自mustache http mustache github com 模板 这些模板是从 URL 下载的 我想对整个 html 结构进行单元测试 JsTestDriver 测试是
  • 并发数据库访问给出 IllegalStateException

    我正在尝试为 1 个方法生成一个线程 我得到一个IllegalStateException 见下文 该方法的作用是接受与数据库的连接和数据库名称 并从中生成 XML 这部分有效 我只是想用一个新线程让它运行得更快 因为我有多个 XML 文件
  • Foreach 循环中的多个变量 [PowerShell]

    是否可以将两个变量放入 Foreach 循环中 以下是针对 PowerShell ASP 的编码 我的 Foreach 循环中的语法不正确 但您应该能够破译我试图构建的逻辑 list Get QADUser userid includeAl
  • XCTest:运行测试失败,且 Cycle inside X;在使用 CocoaPods 和 Carthage 的项目中,构建可能会产生不可靠的结果

    将我的项目升级到 Xcode 12 后 测试套件停止工作 测试目标无法编译 失败并显示 Cycle inside
  • Angular URL“trustAsResourceUrl”不起作用

    我在用着角度文件上传 js https github com nervgh angular file upload并上传图像 上传成功后 它会返回图像托管位置的 URL 该图像在 Azure 上作为 blob 托管 上传成功 并且正确返回
  • 如何搜索不在任何html标签中的url,然后将其转换为超链接?

    所以我的问题是 在相同的内容中有 iframe 图像标签等 它们都有正则表达式匹配 可以将它们转换为正确的格式 最后剩下的就是普通的 URL 我需要一个正则表达式 它将找到所有只是链接而不是在 iframe img 或任何其他标签内的链接
  • 在 Swing 应用程序中仅使用 JavaFX 触摸事件

    有没有办法在 swing 应用程序中使用 JavaFX 触摸事件 目前我正在使用 JFXPanel 来捕获 JavaFX 事件 但是当我尝试获取事件时 我没有收到任何触摸事件 而只收到鼠标事件 这是在 Windows 8 1 戴尔触摸屏上进
  • 如何在 C# 中确定进程的所有者?

    我正在寻找名为 MyApp exe 的进程 并且我想确保获得特定用户拥有的进程 我使用以下代码来获取进程列表 Process processes Process GetProcessesByName MyApp 这给了我一个进程列表 但是
  • UITextView - 使用 NSBackgroundColor 突出显示文本 - 排除换行符

    我有一个带有文本突出显示的工作功能 问题是它还突出显示换行符 看图片 下面是我用来突出显示的函数 void setHighlight set highlighted block BOOL textIsHighlited YES self a
  • 将房间数据库存储在 Google Drive 应用程序文件夹中?

    我还不熟悉Room https developer android com topic libraries architecture room html和 Google Drive API 我想知道是否可以创建 Room 数据库并将其存储在
  • 信号好的情况下GPS更新间隔越快?

    我试图限制我的程序每 10 秒更新一次位置 而不是不断更新 以减少电池消耗 当我在室内调试且信号较弱 即 GPS 图标闪烁 时 此方法工作正常 但如果手机得到正确修复 即 GPS 图标静态 更新间隔会增加到大约一秒 我知道代码mLocati
  • 如何在 FILTERXML 中连接 XML 子级

    我可能有这样的 XML 字符串
  • REST如何实现多态POST端点:抽象类型需要映射到具体的JSON类型

    我从事 SpringBoot 应用程序的工作 我有以下类层次结构 public abstract class DlqMessage Long id UUID employeeId EventReason reason public clas