Próbuję OPUBLIKOWAĆ List
obiekty niestandardowe. Mój kod JSON w treści żądania to:
{
"collection": [
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
}
Kod po stronie serwera obsługujący żądanie:
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();
}
}
Podmiot 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() + "]";
}
}
Ale wyjątek jest rzucany:
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)
Zamiast dokumentu JSON możesz zaktualizować obiekt ObjectMapper jak poniżej:
źródło
To zadziała:
Problem może wystąpić, gdy próbujesz odczytać listę z jednym elementem jako JsonArray, a nie JsonNode lub odwrotnie.
Ponieważ nie możesz być pewien, czy zwrócona lista zawiera pojedynczy element (więc json wygląda tak {...} ), czy wiele elementów (a json wygląda tak: [{...}, {... }] ) - będziesz musiał sprawdzić w czasie wykonywania typ elementu.
To powinno wyglądać tak:
(Uwaga: w tym przykładzie kodu używam com.fasterxml.jackson)
źródło
W związku z odpowiedzią Eugena, możesz rozwiązać ten konkretny przypadek, tworząc obiekt opakowujący POJO, który zawiera
Collection<COrder>
zmienną składową a. To właściwie poprowadzi Jacksona do umieszczenia rzeczywistegoCollection
danych w zmiennej składowej POJO i wygenerowania JSON, którego szukasz w żądaniu API.Przykład:
Następnie ustaw typ parametru
COrderRestService.postOrder()
na nowyApiRequest
POJO opakowania zamiastCollection<COrder>
.źródło
Ostatnio napotkałem ten sam problem i może trochę więcej szczegółów może pomóc komuś innemu.
Szukałem wskazówek dotyczących bezpieczeństwa dla interfejsów API REST i napotkałem bardzo intrygujący problem z tablicami json. Sprawdź łącze, aby uzyskać szczegółowe informacje, ale zasadniczo powinieneś zawinąć je w obiekt, jak już widzieliśmy w tym pytaniu.
Więc zamiast:
Wskazane jest, abyśmy zawsze:
Jest to całkiem proste, gdy wykonujesz GET , ale może sprawić ci trochę problemów, jeśli zamiast tego spróbujesz POST / PUT tego samego pliku json.
W moim przypadku miałem więcej niż jeden GET, który był listą i więcej niż jeden POST / PUT , który otrzymywałby ten sam plik json.
Więc to, co ostatecznie zrobiłem, to użycie bardzo prostego obiektu Wrapper dla listy :
Serializacja moich list została wykonana za pomocą @ControllerAdvice :
Tak więc wszystkie listy i mapy były opakowane w obiekt danych, jak poniżej:
Deserializacja była nadal domyślna, po prostu używano de Wrapper Object:
To było to! Mam nadzieję, że to komuś pomoże.
Uwaga: przetestowano z SpringBoot 1.5.5.RELEASE .
źródło
Miałem ten problem na REST API, które zostało utworzone przy użyciu Spring Framework. Dodanie adnotacji @ResponseBody (w celu utworzenia odpowiedzi JSON) rozwiązało problem.
źródło
Zwykle mamy do czynienia z tym problemem, gdy występuje problem z mapowaniem węzła JSON na węzeł Java. Napotkałem ten sam problem, ponieważ w swaggerze węzeł został zdefiniowany jako tablica Type, a obiekt JSON miał tylko jeden element, stąd system miał trudności z mapowaniem jednej listy elementów do tablicy.
W Swagger element został zdefiniowany jako
Tak powinno być
I
TestNew
powinien być typu tablicaźródło
źródło
Ten sam problem:
Przyczyny tego były następujące:
W moim teście celowo ustawiłem żądanie jako null (brak treści POST). Jak wspomniano wcześniej, przyczyna OP była taka sama, ponieważ żądanie nie zawierało prawidłowego kodu JSON, więc nie mogło zostać automatycznie zidentyfikowane jako żądanie aplikacji / json, co było ograniczeniem na serwerze (
consumes = "application/json"
). Prawidłowe żądanie JSON byłoby. Naprawiono to, że jawne wypełnianie jednostki z null body i nagłówkami JSON.źródło
W moim przypadku błąd był wyświetlany, ponieważ kiedy czytałem plik JSON przy użyciu biblioteki Jacksona, mój plik JSON zawierał tylko 1 obiekt. Dlatego zaczęło się od „{” i kończyło na „}”. Ale czytając go i zapisując w zmiennej, przechowywałem go w obiekcie Array (tak jak w moim przypadku może być więcej niż 1 obiekt).
Dlatego dodałem „[” na początku i „]” na końcu mojego pliku JSON, aby przekonwertować go na tablicę obiektów i działało doskonale bez żadnego błędu.
źródło
Jak wspomniano powyżej, poniższe rozwiązania rozwiązałyby problem:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
Jednak w moim przypadku dostawca zrobił to [0..1] lub [0 .. *] serializacji raczej jako błąd i nie mogłem wymusić naprawy. Z drugiej strony nie chciał wpływać na mój ścisły program mapujący dla wszystkich innych przypadków, które wymagają ścisłej weryfikacji.
Zrobiłem więc Jacksona NASTY HACK (którego generalnie nie powinno się kopiować ;-)), zwłaszcza, że mój SingleOrListElement miał tylko kilka właściwości do załatania:
źródło
@JsonFormat (z = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) prywatne zamówienia Lista <COrder>;
źródło