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类型 的相关文章

  • 垃圾收集器如何在幕后工作来收集死对象?

    我正在阅读有关垃圾收集的内容 众所周知 垃圾收集会收集死亡对象并回收内存 我的问题是 Collector 如何知道任何对象已死亡 它使用什么数据结构来跟踪活动对象 我正在研究这个问题 我发现GC实际上会跟踪活动对象 并标记它们 每个未标记的
  • 从 MATLAB 调用 Java?

    我想要Matlab程序调用java文件 最好有一个例子 需要考虑三种情况 Java 内置库 也就是说 任何描述的here http docs oracle com javase 6 docs api 这些项目可以直接调用 例如 map ja
  • 如何在单个查询中搜索 RealmObject 的 RealmList 字段

    假设我有一堂课 public class Company extends RealmObject private String companyId private RealmList
  • 在 Java 中如何找出哪个对象打开了文件?

    我需要找出答案哪个对象在我的 Java 应用程序中打开了一个文件 这是为了调试 因此欢迎使用工具或实用程序 如果发现哪个对象太具体了 这class也会很有帮助 这可能很棘手 您可以从使用分析器开始 例如VisualVM http visua
  • 如何在java中将日期格式从YYMMDD更改为YYYY-MM-DD? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我从机器可读代码中获取日期格式为 YYMMDD 如何将其更改为 YYYY MM DD 例如我收到 871223 YYMMDD 我想把它改成
  • 如何仅从 Firestore 获取最新更新的数据?

    在 Firestore 上发现任何更改时始终获取整个文档 如何只获取最近更新的数据 这是我的数据 我需要在第一次加载时在聊天中按对象顺序 例如 2018 09 17 30 40 msg和sendby 并且如果数据更新则仅获取新的msg和se
  • 如何在.NET中使用java.util.zip.Deflater解压缩放气流?

    之后我有一个转储java util zip Deflater 可以确认它是有效的 因为 Java 的Inflater打开它很好 并且需要在 NET中打开它 byte content ReadSample sampleName var inp
  • 如何将 HTML 链接放入电子邮件正文中?

    我有一个可以发送邮件的应用程序 用 Java 实现 我想在邮件中放置一个 HTML 链接 但该链接显示为普通字母 而不是 HTML 链接 我怎样才能将 HTML 链接放入字符串中 我需要特殊字符吗 太感谢了 Update 大家好你们好 感谢
  • 如何在JPanel中设置背景图片

    你好 我使用 JPanel 作为我的框架的容器 然后我真的想在我的面板中使用背景图片 我真的需要帮助 这是我到目前为止的代码 这是更新 请检查这里是我的代码 import java awt import javax swing import
  • 不可变的最终变量应该始终是静态的吗? [复制]

    这个问题在这里已经有答案了 在java中 如果一个变量是不可变的并且是final的 那么它应该是一个静态类变量吗 我问这个问题是因为每次类的实例使用它时创建一个新对象似乎很浪费 因为无论如何它总是相同的 Example 每次调用方法时都会创
  • hibernate 6.0.2.Final 和 spring boot 2.7.0 的entityManagerFactory bean 未配置问题

    所以最近我想升级我的 Spring Boot 项目项目的一些依赖项 特别是这些组件 雅加达 EE 9 弹簧靴2 7 休眠 6 0 2 Final 完成此操作后 所有更新和代码折射 更新将 javax 导入到 jakarta 以及一些 hib
  • 为什么\0在java中不同系统中打印不同的输出

    下面的代码在不同的系统中打印不同的输出 String s hello vsrd replace 0 System out println s 当我在我的系统中尝试时 Linux Ubuntu Netbeans 7 1 它打印 When I
  • Spring Boot中ServletContext初始化后如何创建bean?

    我有一个 bean 它实现 ServletContextAware 和 BeanFactoryPostProcessor 接口 我需要在 ServletContext 完成初始化后将此 bean 注册到 applicationContext
  • Hibernate 本机查询 - char(3) 列

    我在 Oracle 中有一个表 其中列 SC CUR CODE 是 CHAR 3 当我做 Query q2 em createNativeQuery select sc cur code sc amount from sector cost
  • Java/Python 中的快速 IPC/Socket 通信

    我的应用程序中需要两个进程 Java 和 Python 进行通信 我注意到套接字通信占用了 93 的运行时间 为什么通讯这么慢 我应该寻找套接字通信的替代方案还是可以使其更快 更新 我发现了一个简单的修复方法 由于某些未知原因 缓冲输出流似
  • 如何更改 Spring OAuth2 上的response_type

    这是我使用 Instagram 进行 OAuth2 登录的配置 instagram client clientId clientId clientSecret clientSeret accessTokenUri https api ins
  • Java 11 - 将 Spring @PostConstruct 替换为 afterPropertiesSet 或使用 initMethod

    我正在使用 spring 应用程序 有时会使用 PostConstruct用于代码和测试中的设置 看来注释将被排除在外Java 11 https www baeldung com spring postconstruct predestro
  • 由 Servlet 容器提供服务的 WebSocket

    上周我研究了 WebSockets 并对如何使用 Java Servlet API 实现服务器端进行了一些思考 我没有花费太多时间 但在使用 Tomcat 进行一些测试时遇到了以下问题 如果不修补容器或至少对 HttpServletResp
  • java'assert'和'if(){}else exit;'之间的区别

    java和java有什么区别assert and if else exit 我可以用吗if else exit代替assert 也许有点谷歌 您应该记住的主要事情是 if else 语句应该用于程序流程控制 而assert 关键字应该仅用于
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

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

    这个问题在这里已经有答案了 假设我有 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