基于对象类型反序列化JSON

我正在创建一个以JSON消息的forms接收请求的服务。 我需要解析消息并根据请求类型采取适当的操作。 例如(伪代码):

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