不能从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 { ... }