Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java REST如何实现多态POST端点:抽象类型需要映射到具体类型_Java_Spring_Rest - Fatal编程技术网

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

Java REST如何实现多态POST端点:抽象类型需要映射到具体类型,java,spring,rest,Java,Spring,Rest,我在一个SpringBoot应用程序上工作 我有以下类层次结构: public abstract class DlqMessage { Long id; UUID employeeId; EventReason reason; } public class ContractUpdateMessage extends DlqMessage {} public class SingleContractUpdateMessage extends DlqMessage {

我在一个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
SingleContractUpdateMessage
仅在几个字段上有所不同

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

@PostMapping("/messages")
public ResponseEntity<DlqMessage> create(@RequestBody DlqMessage contractUpdateMessage) {
    DlqMesssage dlqEntry = dlqEntityService.save(contractUpdateMessage);
    return ResponseEntity.ok(dlqEntry);
}
然后我有一个测试助手类,它使用RestTemplate向控制器发送POST请求:

ResponseEntity<DlqMesssage> response =
                crudRestClient.post("/messages/contract", message, DlqMesssage.class, null);
        return response.getBody();
看起来我的请求甚至不是由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);
}
@PostMapping(“/messages/contract”)
公共响应创建(@RequestBody ContractUpdateMessage ContractUpdateMessage){
ContractUpdateMessage dlqEntry=(ContractUpdateMessage)dlqEntityService.save(ContractUpdateMessage);
返回响应正确(dlqEntry);
}
@后映射(“/messages/single”)
公共响应创建(@RequestBody SingleContractUpdateMessage contractUpdateMessage){
SingleContractUpdateMessage dlqEntry=(SingleContractUpdateMessage)dlqEntityService.save(contractUpdateMessage);
返回响应正确(dlqEntry);
}
然而,这看起来很难看,不是一个“正确”的解决方案


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

您可以使用jackson映射来映射类。在类中添加类型属性

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

问题在于spring正试图直接从输入负载创建DlqMessage的实例。假设您的API接受JSON输入,您需要指示JSON解析器如何根据有效负载内容区分子类型

这里有一个类似问题的链接,展示了如何使用jackson json实现这一点的示例。看起来您必须通过
@JsonSubTypes
用子类型的知识注释抽象类,并通过
@JsonTypeInfo
提供区分字段:


无法使用抽象类型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

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

@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 { ... }
{
  "id":300, 
  "employeeId":"d6a00fb2-058c-4bf7-9a0a-7cc538cd85f5",
  "messageType":"ContractUpdateMessage"
}