簡體   English   中英

基於對象類型反序列化JSON

[英]Deserializing JSON based on object type

我正在創建一個以JSON消息的形式接收請求的服務。 我需要解析消息並根據請求類型采取適當的操作。 例如(偽代碼):

switch(request.type) {
    case "NewOrder":
        createNewOrder(order);
        break;
    case "CancelOrder"
        cancelOrder(orderId);
        break;
}

似乎大多數JSON API(至少那些為您執行對象映射的API)需要根對象類型來反序列化。 這周圍有什么優雅的方式嗎?

例如,在Jackson API(使用完整對象映射)中,我需要調用mapper,如下所示:

NewOrder newOrder = mapper.readValue(src, NewOrder.class);
CancelOrder cancelOrder = mapper.readValue(src. CancelOrder.class);

這意味着我需要在解析之前知道對象的類。 我真正需要的是一些方法來查看JSON字符串,確定請求類型,然后調用適當的readValue()方法 - 如下所示:

String requestType = getRequestType(src);
switch(request.type) {
    case "NewOrder":
        NewOrder newOrder = mapper.readValue(src, NewOrder.class);
        createNewOrder(newOrder.order);
        break;
    case "CancelOrder"
        CancelOrder cancelOrder = mapper.readValue(src. CancelOrder.class);
        cancelOrder(cancelOrder.orderId);
        break;
}

是否可以使用Jackson或任何其他Java JSON解析器執行此操作? 我確信我可以使用流API或基於節點的API,但我可以嘗試避免這種復雜性。

如果您使用Jackson將JSON輸入解析為Map,則可以快速訪問類型信息。 然后,您可以將對象創建為必需的類,並使用ObjectMapper.convert從您從Jackson獲得的Map配置對象。

這是一個例子:

public class Test1 {
private String f;
private String b;

public void setFoo(String v) { f = v; }

public void setBim(String v) { b = v; }

public String toString() { return "f=" + f + ", b=" + b; }


public static void main(String[] args) throws Exception {
    String test = "{ \"foo\":\"bar\", \"bim\":\"baz\" }";
    ObjectMapper mapper = new ObjectMapper();
    HashMap map = mapper.readValue(new StringReader(test), HashMap.class);
    System.out.println(map);
    Test1 test1 = mapper.convertValue(map, Test1.class);
    System.out.println(test1);
}
}

您可以在訂單周圍使用包裝:

{
"NewOrder": {...}
}

要么

{
"CancelOrder": {...}
}

更新:

class Wrapper {
    newOrder: NewOrder;
    cancelOrderId: Integer;
}

Wrapper wrapper = mapper.readValue(src, Wrapper.class);

if (wrapper.newOrder != null) {
    createNewOrder(wrapper.newOrder);
}
if (wrapper.cancelOrderId != null) {
    cancelOrder(wrapper.cancelOrderId);
}

假設訂單只是數據,將責任委托給DoSomethingService並通過工廠生產服務可能會有所幫助:

Service service = takeActionFactory
    .buildTheRightServiceForTheValue(src);
service.takeAction();

工廠將解析JSON對象:

Service buildTheRightServiceForTheValue(src) {
    switch(request.type) {
    case "NewOrder":
        return new NewOrderService(mapper.readValue(src, NewOrder.class)); 
        break;
    case "CancelOrder"
        return new CancelOrderService(mapper.readValue(src. CancelOrder.class));
        break;
    }
    case "SomeOtherObject"
        return new SomeOtherService(mapper.readValue(src, SomeOtherService.class));
    }

具體服務是服務的子類:

NewOrderService implements Service {
    private final NewOrder newOrder;
    /**constructor*/
    ...

    void takeAction() {
        createNewOrder(newOrder.order);
    }
}

謝謝Maurice,Simon和nzroller。 結合您所有回復的想法,我提出了解決方案。 歡迎反饋。

public enum MessageType {
    NewOrder,
    CancelOrder
}

public class JsonMessage {
    private MessageType messageType;
    private Object payload;
    ...
}

public class Order {
    private String orderId;
    private String itemId;
    private int quantity;
    ...
}

public class NewOrder {
    private Order order;
    ...
}

public class CancelOrder {
    private String orderId;
    ...
}

以下是序列化NewOrder的方法:

JsonMessage jsonMessage =
    new JsonMessage(MessageType.NewOrder, newOrder);
ObjectMapper mapper = new ObjectMapper();
String jsonMessageString = mapper.writeValueAsString(jsonMessage);

為了反序列化,我首先將JSON字符串讀入JsonNode的樹中。 然后我讀了messageType。 最后,根據消息類型,我直接將有效負載讀取為Java對象。

JsonNode rootNode = mapper.readValue(jsonMessageString, JsonNode.class);

MessageType messageType =
    MessageType.valueOf(rootNode.path("messageType").getTextValue());

switch(messageType) {
    case NewOrder:
        NewOrder newOrder = mapper.readValue(
                rootNode.path("payload"), NewOrder.class);
        myOrderService.placeOrder(newOrder.getOrder());
        break;

    case CancelOrder:
        CancelOrder cancelOrder = mapper.readValue(
                rootNode.path("payload"), CancelOrder.class);
        myOrderService.cancelOrder(cancelOrder.getOrderId());
        break;
}

將 json 反序列化為列表<object><div id="text_translate"><p>我有 json:</p><pre> "taxLevels": [{ "code": "VAT", "percentage": 19.0 } ]</pre><p> 這確實是List&lt;TTaxLevel&gt;</p><p> 我有<strong>Model.class</strong> :</p><pre> public class Model{ private final List&lt;TTaxLevel&gt; taxLevels; }</pre><p> 和<strong>TtaxLevel.class</strong> :</p><pre> @NoArgsConstructor public class TTaxLevel { private String code; private Double percentage; }</pre><p> 但我在這里收到錯誤:</p><blockquote><p> [Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of java.util.LinkedHashMap&lt;java.lang.String,java.lang.String&gt; out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.LinkedHashMap&lt;java.lang.String,java.lang.String&gt; out of START_ARRAY token at [Source: (PushbackInputStream); 行:36,列:19](通過參考鏈:...Model["taxLevels"])]]</p></blockquote><p> 我可以以某種方式強制jackson在這里ArrayList而不是Map嗎? 這是一個問題。</p><p> 這是反序列化代碼:</p><pre> Model model = new ObjectMapper().readValue(content, Model.class);</pre></div></object>

[英]Deserializing json as List<Object>

暫無
暫無

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

相關問題 使用基於JSON類型的Jackson進行反序列化 反序列化JSON對象 將 json 反序列化為列表<object><div id="text_translate"><p>我有 json:</p><pre> "taxLevels": [{ "code": "VAT", "percentage": 19.0 } ]</pre><p> 這確實是List&lt;TTaxLevel&gt;</p><p> 我有<strong>Model.class</strong> :</p><pre> public class Model{ private final List&lt;TTaxLevel&gt; taxLevels; }</pre><p> 和<strong>TtaxLevel.class</strong> :</p><pre> @NoArgsConstructor public class TTaxLevel { private String code; private Double percentage; }</pre><p> 但我在這里收到錯誤:</p><blockquote><p> [Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of java.util.LinkedHashMap&lt;java.lang.String,java.lang.String&gt; out of START_ARRAY token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.util.LinkedHashMap&lt;java.lang.String,java.lang.String&gt; out of START_ARRAY token at [Source: (PushbackInputStream); 行:36,列:19](通過參考鏈:...Model["taxLevels"])]]</p></blockquote><p> 我可以以某種方式強制jackson在這里ArrayList而不是Map嗎? 這是一個問題。</p><p> 這是反序列化代碼:</p><pre> Model model = new ObjectMapper().readValue(content, Model.class);</pre></div></object> 反序列化並非始終屬於同一類型的 json object 反序列化JSON時確定類型 根據ID反序列化父對象 使用LocalDateTime字段將JSON反序列化為對象 用傑克遜反序列化嵌套的json對象 將多態 Json object 反序列化為 POJO 用Jackson反序列化具有通用類型的對象
 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM