不能从START_OBJECT标记反序列化java.util.ArrayList的实例

我试图发布自定义对象的List 。 请求正文中的我的JSON是这样的:

 { "collection": [ { "name": "Test order1", "detail": "ahk ks" }, { "name": "Test order2", "detail": "Fisteku" } ] } 

处理请求的服务器端代码:

 import java.util.Collection; import javax.ws.rs.Consumes; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; @Path(value = "/rest/corder") public class COrderRestService { @POST @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public Response postOrder(Collection<COrder> orders) { StringBuilder stringBuilder = new StringBuilder(); for (COrder c : orders) { stringBuilder.append(c.toString()); } System.out.println(stringBuilder); return Response.ok(stringBuilder, MediaType.APPLICATION_JSON).build(); } } 

实体COrder

 import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class COrder { String name; String detail; @Override public String toString() { return "COrder [name=" + name + ", detail=" + detail + ", getClass()=" + getClass() + ", hashCode()=" + hashCode() + ", toString()=" + super.toString() + "]"; } } 

但是抛出一个exception:

 SEVERE: Failed executing POST /rest/corder org.jboss.resteasy.spi.ReaderException: org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token at [Source: org.apache.catalina.connector.CoyoteInputStream@6de8c535; line: 1, column: 1] at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:183) at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:88) at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:111) at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:280) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:234) at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:221) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356) at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179) at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51) at javax.servlet.http.HttpServlet.service(HttpServlet.java:728) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) at java.lang.Thread.run(Thread.java:724) 

问题是JSON – 默认情况下,它不能被反序列化为一个Collection因为它实际上不是一个JSON数组 – 它看起来像这样:

 [ { "name": "Test order1", "detail": "ahk ks" }, { "name": "Test order2", "detail": "Fisteku" } ] 

既然你没有控制反序列化的确切过程(RestEasy做的), 第一个select是简单地将JSON注入为一个String ,然后控制反序列化过程:

 Collection<COrder> readValues = new ObjectMapper().readValue(jsonAsString, new TypeReference<Collection<COrder>>() { }); 

你可能会失去一点自己不需要的便利,但是你很容易理清这个问题。

另一个select – 如果你不能改变JSON的话 – 将会构造一个适合你的JSONinput结构的包装,并使用它来代替Collection<COrder>

希望这可以帮助。

这将工作:

当你试图读取一个单一元素作为JsonArray而不是JsonNode或反之亦然时,可能会发生问题。

因为你不知道如果返回的列表包含单个元素(所以json看起来像这个{…}或多个元素(和json看起来像这样[{…},{… }] – 你必须在运行时检查元素的types。

它应该是这样的:

(注意:在这个代码示例中我使用的是com.fasterxml.jackson)

 String jsonStr = response.readEntity(String.class); ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(jsonStr); // Start by checking if this is a list -> the order is important here: if (rootNode instanceof ArrayNode) { // Read the json as a list: myObjClass[] objects = mapper.readValue(rootNode.toString(), myObjClass[].class); ... } else if (rootNode instanceof JsonNode) { // Read the json as a single object: myObjClass object = mapper.readValue(rootNode.toString(), myObjClass.class); ... } else { ... }