簡體   English   中英

REST 如何實現多態 POST 端點:抽象類型需要映射到具體類型

[英]REST How to implement polymorphic POST end point: abstract types need to be mapped to concrete types

我在 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;
}

因此,類ContractUpdateMessageSingleContractUpdateMessage僅在幾個字段上有所不同。

我有一個 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

問題是 spring 試圖直接從輸入負載創建 DlqMessage 的實例。 假設您的 API 接受 JSON 輸入,您需要指示您的 json 解析器如何根據有效負載內容區分子類型。

這是一個類似問題的鏈接,該鏈接顯示了如何使用 jackson json 執行此操作的示例。 像你看上去就必須通過注釋與亞型知識的抽象類@JsonSubTypes以及提供通過區分領域@JsonTypeInfo

https://stackoverflow.com/a/27183383/1563240

你可以用jackson mapping來映射類。 在類中添加類型屬性。

@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 {

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM