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