Saya mencoba untuk POST List
objek kustom. JSON saya di badan permintaan adalah ini:
{
"collection": [
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
}
Kode sisi server yang menangani permintaan:
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();
}
}
Entitas 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() + "]";
}
}
Tapi ada pengecualian:
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)
Alih-alih dokumen JSON, Anda dapat memperbarui objek ObjectMapper seperti di bawah ini:
sumber
Ini akan berhasil:
Masalahnya mungkin terjadi saat Anda mencoba membaca daftar dengan satu elemen sebagai JsonArray daripada JsonNode atau sebaliknya.
Karena Anda tidak dapat mengetahui dengan pasti apakah daftar yang dikembalikan berisi satu elemen (jadi json terlihat seperti ini {...} ) atau beberapa elemen (dan json terlihat seperti ini [{...}, {... }] ) - Anda harus memeriksa dalam runtime jenis elemen.
Ini akan terlihat seperti ini:
(Catatan: dalam contoh kode ini saya menggunakan com.fasterxml.jackson)
sumber
Terkait dengan jawaban Eugen, Anda dapat menyelesaikan kasus khusus ini dengan membuat objek POJO pembungkus yang berisi
Collection<COrder>
variabel anggotanya. Ini akan memandu Jackson dengan benar untuk menempatkanCollection
data aktual di dalam variabel anggota POJO dan menghasilkan JSON yang Anda cari dalam permintaan API.Contoh:
Kemudian atur jenis parameter
COrderRestService.postOrder()
menjadiApiRequest
POJO pembungkus baru Anda, bukanCollection<COrder>
.sumber
Saya mengalami masalah yang sama akhir-akhir ini dan mungkin beberapa detail lebih lanjut mungkin dapat membantu orang lain.
Saya sedang mencari beberapa pedoman keamanan untuk REST API dan mengatasi masalah yang sangat menarik dengan json array. Periksa tautan untuk detailnya, tetapi pada dasarnya, Anda harus membungkusnya di dalam Objek seperti yang telah kita lihat di pertanyaan posting ini.
Jadi, alih-alih:
Sangat disarankan agar kami selalu melakukan:
Ini sangat mudah ketika Anda melakukan GET , tetapi mungkin memberi Anda masalah jika, sebaliknya, Anda mencoba POST / PUT json yang sama.
Dalam kasus saya, saya memiliki lebih dari satu GET yang merupakan Daftar dan lebih dari satu POST / PUT yang akan menerima json yang sama.
Jadi yang akhirnya saya lakukan adalah menggunakan objek Wrapper yang sangat sederhana untuk List :
Serialisasi daftar saya dibuat dengan @ControllerAdvice :
Jadi, semua Daftar dan Peta yang dibungkus di atas objek data seperti di bawah ini:
Deserialization masih default, hanya menggunakan de Wrapper Object:
Itu dia! Semoga membantu seseorang.
Catatan: diuji dengan SpringBoot 1.5.5.RELEASE .
sumber
Saya mengalami masalah ini di REST API yang dibuat menggunakan framework Spring. Menambahkan anotasi @ResponseBody (untuk membuat tanggapan JSON) menyelesaikannya.
sumber
Biasanya kita menghadapi masalah ini ketika ada masalah dalam memetakan node JSON dengan objek Java. Saya menghadapi masalah yang sama karena dalam kesombongan node didefinisikan sebagai Type array dan objek JSON hanya memiliki satu elemen, oleh karena itu sistem mengalami kesulitan dalam memetakan satu daftar elemen ke array.
Di Swagger, elemen didefinisikan sebagai
Padahal seharusnya
Dan
TestNew
harus bertipe arraysumber
sumber
Masalah yang sama:
Penyebabnya adalah sebagai berikut:
Dalam pengujian saya, saya sengaja menetapkan permintaan sebagai null (tanpa POST konten). Seperti yang disebutkan sebelumnya, penyebab OP sama karena permintaan tersebut tidak berisi JSON yang valid, sehingga tidak dapat secara otomatis diidentifikasi sebagai permintaan application / json yang merupakan batasan pada server (
consumes = "application/json"
). Permintaan JSON yang valid adalah. Yang memperbaikinya adalah mengisi entitas dengan badan null dan header json secara eksplisit.sumber
Dalam kasus saya, kesalahan ditampilkan karena ketika saya membaca file JSON saya menggunakan pustaka Jackson, file JSON saya hanya berisi 1 objek. Oleh karena itu, ini dimulai dengan "{" dan diakhiri dengan "}". Tetapi saat membaca dan menyimpannya dalam variabel, saya menyimpannya dalam objek Array (Seperti dalam kasus saya, mungkin ada lebih dari 1 objek).
Oleh karena itu, saya menambahkan "[" di awal dan "]" di akhir file JSON saya untuk mengubahnya menjadi array objek dan itu bekerja dengan baik tanpa kesalahan.
sumber
Seperti disebutkan di atas, berikut ini akan menyelesaikan masalah:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
Namun dalam kasus saya, penyedia melakukan serialisasi [0..1] atau [0 .. *] ini sebagai bug dan saya tidak dapat memaksakan perbaikan. Di sisi lain, itu tidak ingin memengaruhi pembuat peta ketat saya untuk semua kasus lain yang perlu divalidasi secara ketat.
Jadi saya melakukan Jackson NASTY HACK (yang tidak boleh disalin secara umum ;-)), terutama karena SingleOrListElement saya hanya memiliki beberapa properti untuk ditambal:
sumber
@JsonFormat (with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) private List <COrder> orders;
sumber