Ich versuche, ein List
benutzerdefiniertes Objekt zu POSTEN . Mein JSON im Anfragetext lautet:
{
"collection": [
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
}
Serverseitiger Code, der die Anforderung verarbeitet:
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();
}
}
Entität 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() + "]";
}
}
Aber eine Ausnahme wird geworfen:
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)
Anstelle des JSON-Dokuments können Sie das ObjectMapper-Objekt wie folgt aktualisieren:
quelle
Das wird funktionieren:
Das Problem kann auftreten, wenn Sie versuchen, eine Liste mit einem einzelnen Element als JsonArray und nicht als JsonNode zu lesen oder umgekehrt.
Da Sie nicht sicher wissen können, ob die zurückgegebene Liste ein einzelnes Element (der JSON sieht also so aus {...} ) oder mehrere Elemente (und der JSON so aussieht [{...}, {... }] ) - Sie müssen zur Laufzeit den Typ des Elements überprüfen.
Es sollte so aussehen:
(Hinweis: In diesem Codebeispiel verwende ich com.fasterxml.jackson.)
quelle
In Bezug auf Eugens Antwort können Sie diesen speziellen Fall lösen, indem Sie ein Wrapper-POJO-Objekt erstellen, das eine
Collection<COrder>
als Mitgliedsvariable enthält . Dies wird Jackson richtig führen, um das tatsächliche zu platzierenCollection
Daten in die Mitgliedsvariable des POJO zu platzieren und den JSON zu erstellen, nach dem Sie in der API-Anforderung suchen.Beispiel:
Stellen Sie dann den Parametertyp
COrderRestService.postOrder()
als Ihren neuenApiRequest
Wrapper POJO anstelle von einCollection<COrder>
.quelle
Ich bin heutzutage auf dasselbe Problem gestoßen, und vielleicht könnten weitere Details für jemand anderen hilfreich sein.
Ich habe einige Sicherheitsrichtlinien für REST-APIs gesucht und ein sehr interessantes Problem festgestellt mit JSON-Arrays festgestellt. Überprüfen Sie den Link auf Details, aber im Grunde sollten Sie sie in ein Objekt einschließen, wie wir bereits in dieser Beitragsfrage gesehen haben.
Also statt:
Es ist ratsam, dass wir immer tun:
Dies ist ziemlich einfach, wenn Sie ein GET durchführen , kann Ihnen jedoch Probleme bereiten, wenn Sie stattdessen versuchen, denselben JSON zu POSTEN / SETZEN.
In meinem Fall hatte ich mehr als ein GET , das eine Liste war, und mehr als ein POST / PUT , das den gleichen JSON erhalten würde.
Am Ende habe ich also ein sehr einfaches Wrapper- Objekt für eine Liste verwendet :
Die Serialisierung meiner Listen erfolgte mit einem @ControllerAdvice :
Alle Listen und Karten wurden wie folgt über ein Datenobjekt gewickelt :
Die Deserialisierung war immer noch Standard, nur mit de Wrapper Object:
Das war's! Hoffe es hilft jemandem.
Hinweis: getestet mit SpringBoot 1.5.5.RELEASE .
quelle
Ich hatte dieses Problem mit einer REST-API, die mit dem Spring-Framework erstellt wurde. Durch Hinzufügen einer @ ResponseBody-Annotation (um die Antwort JSON zu erstellen) wurde das Problem behoben.
quelle
Normalerweise tritt dieses Problem auf, wenn beim Zuordnen des JSON-Knotens zum Java-Objekt ein Problem auftritt. Ich hatte das gleiche Problem, weil in der Prahlerei der Knoten als Typ-Array definiert war und das JSON-Objekt nur ein Element hatte, weshalb das System Schwierigkeiten hatte, eine Elementliste einem Array zuzuordnen.
In Swagger wurde das Element definiert als
Während es sein sollte
Und
TestNew
sollte vom Typ Array seinquelle
quelle
Gleicher Fehler:
Was es verursachte, war das Folgende:
In meinem Test habe ich die Anfrage absichtlich auf null gesetzt (kein Inhalts-POST). Wie bereits erwähnt, war die Ursache für das OP dieselbe, da die Anforderung keinen gültigen JSON enthielt, sodass sie nicht automatisch als Anwendungs- / JSON-Anforderung identifiziert werden konnte, was die Einschränkung auf dem Server darstellte (
consumes = "application/json"
). Eine gültige JSON-Anfrage wäre. Was behoben wurde, war das explizite Auffüllen einer Entität mit Nullkörper- und JSON-Headern.quelle
In meinem Fall wurde der Fehler angezeigt, da meine JSON-Datei beim Lesen meiner JSON-Datei mit der Jackson-Bibliothek nur 1 Objekt enthielt. Daher begann es mit "{" und endete mit "}". Aber während ich es las und in einer Variablen speicherte, speicherte ich es in einem Array-Objekt (wie in meinem Fall könnte es mehr als ein Objekt geben).
Daher habe ich "[" am Anfang und "]" am Ende meiner JSON-Datei hinzugefügt, um sie in ein Array von Objekten zu konvertieren, und es hat einwandfrei ohne Fehler funktioniert.
quelle
Wie oben erwähnt, würde Folgendes das Problem lösen:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
In meinem Fall hat der Anbieter diese [0..1] oder [0 .. *] Serialisierung jedoch eher als Fehler durchgeführt, und ich konnte die Korrektur nicht erzwingen. Auf der anderen Seite wollte es meinen strengen Mapper nicht für alle anderen Fälle beeinflussen, die streng validiert werden müssen.
Also habe ich einen Jackson NASTY HACK gemacht (der im Allgemeinen nicht kopiert werden sollte ;-)), vor allem, weil mein SingleOrListElement nur wenige Eigenschaften zum Patchen hatte:
quelle
@JsonFormat (mit = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) private List <Corder> -Bestellungen;
quelle