Estoy tratando de publicar un List
objeto personalizado. Mi JSON en cuerpo de solicitud es este:
{
"collection": [
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
}
Código del lado del servidor que maneja la solicitud:
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();
}
}
Entidad 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() + "]";
}
}
Pero se lanza una excepción:
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)
En lugar del documento JSON, puede actualizar el objeto ObjectMapper como se muestra a continuación:
fuente
Esto funcionará:
El problema puede ocurrir cuando intentas leer una lista con un solo elemento como JsonArray en lugar de JsonNode o viceversa.
Como no puede saber con certeza si la lista devuelta contiene un solo elemento (por lo que el json se ve así {...} ) o varios elementos (y el json se ve así [{...}, {... }] ) - deberás comprobar en tiempo de ejecución el tipo de elemento.
Debe tener un aspecto como este:
(Nota: en este ejemplo de código estoy usando com.fasterxml.jackson)
fuente
En relación con la respuesta de Eugen, puede resolver este caso particular creando un objeto POJO de contenedor que contenga a
Collection<COrder>
como su variable miembro. Esto guiará adecuadamente a Jackson para colocar losCollection
datos reales dentro de la variable miembro de POJO y producir el JSON que está buscando en la solicitud de API.Ejemplo:
Luego establezca el tipo de parámetro de
COrderRestService.postOrder()
para que sea su nuevoApiRequest
contenedor POJO en lugar deCollection<COrder>
.fuente
Me encontré con este mismo problema en estos días y tal vez algún detalle más podría ser útil para otra persona.
Estaba buscando algunas pautas de seguridad para las API REST y crucé un problema muy intrigante con las matrices json. Verifique el enlace para obtener detalles, pero básicamente, debe envolverlos dentro de un Objeto como ya vimos en esta pregunta de la publicación.
Entonces, en lugar de:
Es recomendable que siempre hagamos:
Esto es bastante sencillo cuando haces un GET , pero podría darte algunos problemas si, en cambio, intentas PUBLICAR / PONER el mismo json.
En mi caso, tenía más de un GET que era una Lista y más de un POST / PUT que recibiría el mismo json.
Entonces, lo que terminé haciendo fue usar un objeto Wrapper muy simple para una Lista :
La serialización de mis listas se realizó con un @ControllerAdvice :
Entonces, todas las Listas y Mapas se envolvieron sobre un objeto de datos como se muestra a continuación:
La deserialización seguía siendo predeterminada, solo usando el Objeto Wrapper :
¡Eso fue todo! Espero que ayude a alguien.
Nota: probado con SpringBoot 1.5.5.RELEASE .
fuente
Tuve este problema en una API REST que se creó con Spring Framework. Agregar una anotación @ResponseBody (para hacer la respuesta JSON) lo resolvió.
fuente
Normalmente nos enfrentamos a este problema cuando hay un problema al mapear el nodo JSON con el del objeto Java. Me enfrenté al mismo problema porque en el swagger el nodo se definió como tipo de matriz y el objeto JSON tenía solo un elemento, por lo tanto, el sistema tenía dificultades para asignar una lista de elementos a una matriz.
En Swagger, el elemento se definió como
Si bien debería ser
Y
TestNew
debe ser de tipo arrayfuente
fuente
Mismo problema:
Lo que lo causó fue lo siguiente:
En mi prueba, configuré a propósito la solicitud como nula (sin contenido POST). Como se mencionó anteriormente, la causa del OP fue la misma porque la solicitud no contenía un JSON válido, por lo que no se pudo identificar automáticamente como una solicitud de aplicación / json que era la limitación en el servidor (
consumes = "application/json"
). Sería una solicitud JSON válida. Lo que solucionó fue poblar una entidad con cuerpo nulo y encabezados json explícitamente.fuente
En mi caso, el error se mostraba porque cuando estaba leyendo mi archivo JSON usando la biblioteca Jackson, mi archivo JSON contenía solo 1 objeto. Por lo tanto, comenzó con "{" y terminó con "}". Pero mientras lo leía y lo almacenaba en una variable, lo estaba almacenando en un objeto Array (como en mi caso, podría haber más de 1 objeto).
Por lo tanto, agregué "[" al principio y "]" al final de mi archivo JSON para convertirlo en una matriz de objetos y funcionó perfectamente bien sin ningún error.
fuente
Como se mencionó anteriormente, lo siguiente resolvería el problema:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
Sin embargo, en mi caso, el proveedor hizo esta serialización [0..1] o [0 .. *] en lugar de un error y no pude forzar la reparación. Por otro lado, no quería afectar mi mapeador estricto para todos los demás casos que deben validarse estrictamente.
Así que hice un Jackson NASTY HACK (que no debería copiarse en general ;-)), especialmente porque mi SingleOrListElement tenía solo pocas propiedades para parchear:
fuente
@JsonFormat (con = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) Lista privada <COrder> pedidos;
fuente