Impossible de désérialiser l’instance de java.util.ArrayList avec le jeton START_OBJECT

J’essaie de POST une List d’objects personnalisés. Mon JSON dans le corps de la requête est le suivant:

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

Code côté serveur qui gère la demande:

 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 orders) { SsortingngBuilder ssortingngBuilder = new SsortingngBuilder(); for (COrder c : orders) { ssortingngBuilder.append(c.toSsortingng()); } System.out.println(ssortingngBuilder); return Response.ok(ssortingngBuilder, MediaType.APPLICATION_JSON).build(); } } 

Entité COrder :

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

Mais une exception est levée:

 SEVERE: Failed executing POST /rest/corder org.jboss.restasy.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.restasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:183) at org.jboss.restasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:88) at org.jboss.restasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:111) at org.jboss.restasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:280) at org.jboss.restasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:234) at org.jboss.restasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:221) at org.jboss.restasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356) at org.jboss.restasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179) at org.jboss.restasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220) at org.jboss.restasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56) at org.jboss.restasy.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) 

Le problème est le JSON – qui, par défaut, ne peut pas être désérialisé dans une Collection car ce n’est pas vraiment un tableau JSON – cela ressemblerait à ceci:

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

Comme vous ne contrôlez pas le processus exact de désérialisation (RestEasy le fait) – une première option serait d’injecter simplement le JSON en tant que Ssortingng , puis de prendre le contrôle du processus de désérialisation:

 Collection readValues = new ObjectMapper().readValue(jsonAsSsortingng, new TypeReference>() { }); 

Vous perdriez un peu la commodité de ne pas avoir à le faire vous-même, mais vous régleriez facilement le problème.

Une autre option – si vous ne pouvez pas changer le JSON – serait de construire un wrapper pour s’adapter à la structure de votre entrée JSON – et l’utiliser à la place de Collection .

J’espère que cela t’aides.

Cela fonctionnera:

Le problème peut survenir lorsque vous essayez de lire une liste avec un seul élément en tant que JsonArray plutôt que JsonNode ou inversement.

Comme vous ne pouvez pas savoir avec certitude si la liste renvoyée contient un seul élément (le json ressemble à ceci {…} ) ou plusieurs éléments (et le json ressemble à ceci [{…}, {… }] ) – vous devrez vérifier à l’exécution le type de l’élément.

Ça devrait ressembler à ça:

(Remarque: dans cet exemple de code, j’utilise com.fasterxml.jackson)

 Ssortingng jsonStr = response.readEntity(Ssortingng.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.toSsortingng(), myObjClass[].class); ... } else if (rootNode instanceof JsonNode) { // Read the json as a single object: myObjClass object = mapper.readValue(rootNode.toSsortingng(), myObjClass.class); ... } else { ... } 

Au lieu du document JSON, vous pouvez mettre à jour l’object ObjectMapper comme ci-dessous:

 ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); 

J’ai eu ce problème sur une API REST créée à l’aide du framework Spring. L’ajout d’une annotation @ResponseBody (pour que la réponse JSON) le résolve.