Я пытаюсь опубликовать List
пользовательские объекты. Мой JSON в теле запроса таков:
{
"collection": [
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
}
Код на стороне сервера, обрабатывающий запрос:
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();
}
}
Сущность 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() + "]";
}
}
Но возникает исключение:
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)
Вместо документа JSON вы можете обновить объект ObjectMapper, как показано ниже:
источник
Это будет работать:
Проблема может возникнуть, когда вы пытаетесь прочитать список с одним элементом как JsonArray, а не JsonNode, или наоборот.
Поскольку вы не можете точно знать, содержит ли возвращаемый список один элемент (поэтому json выглядит так {...} ) или несколько элементов (а json выглядит так [{...}, {... }] ) - вам нужно будет проверить во время выполнения тип элемента.
Должно получиться так:
(Примечание: в этом примере кода я использую com.fasterxml.jackson)
источник
В связи с ответом Евгения вы можете решить этот конкретный случай, создав объект POJO-оболочки, который содержит в
Collection<COrder>
качестве своей переменной-члена. Это правильно поможет Джексону поместить фактическиеCollection
данные в переменную-член POJO и создать JSON, который вы ищете в запросе API.Пример:
Затем установите тип параметра
COrderRestService.postOrder()
как вашу новуюApiRequest
оболочку POJO вместоCollection<COrder>
.источник
В эти дни я столкнулся с той же проблемой, и, возможно, некоторые подробности могут быть полезны кому-то другому.
Я искал некоторые рекомендации по безопасности для REST API и преодолел очень интригующую проблему с массивами json. Проверьте ссылку для получения подробной информации, но в основном вы должны заключить их в объект, как мы уже видели в этом вопросе публикации.
Итак, вместо:
Желательно, чтобы мы всегда делали:
Это довольно просто, когда вы выполняете GET , но может вызвать некоторые проблемы, если вместо этого вы попытаетесь выполнить POST / PUT тот же самый json.
В моем случае у меня было более одного GET, который был списком, и более одного POST / PUT , которые получали бы один и тот же json.
В итоге я использовал очень простой объект Wrapper для списка :
Сериализация моих списков была произведена с помощью @ControllerAdvice :
Итак, все списки и карты были обернуты поверх объекта данных, как показано ниже:
Десериализация по-прежнему была по умолчанию, просто использовался объект de Wrapper :
Вот и все! Надеюсь, это кому-то поможет.
Примечание: протестировано с помощью SpringBoot 1.5.5.RELEASE .
источник
У меня была эта проблема с REST API, созданным с использованием Spring framework. Добавление аннотации @ResponseBody (чтобы сделать ответ JSON) разрешило это.
источник
Обычно мы сталкиваемся с этой проблемой, когда возникает проблема сопоставления узла JSON с узлом Java-объекта. Я столкнулся с той же проблемой, потому что в чванстве узел был определен как массив типа, а объект JSON имел только один элемент, поэтому система испытывала трудности с отображением одного списка элементов в массив.
В Swagger элемент был определен как
Хотя должно быть
И
TestNew
должен быть типа arrayисточник
источник
Та же проблема:
Причиной этого было следующее:
В моем тесте я намеренно установил запрос как null (без POST содержимого). Как упоминалось ранее, причина для OP была та же, потому что запрос не содержал действительного JSON, поэтому он не мог быть автоматически идентифицирован как запрос application / json, что было ограничением на сервере (
consumes = "application/json"
). Действительный запрос JSON будет. Что исправлено, так это явное заполнение объекта нулевым телом и заголовками json.источник
В моем случае ошибка отображалась, потому что, когда я читал свой файл JSON с использованием библиотеки Джексона, мой файл JSON содержал только 1 объект. Следовательно, он начинается с "{" и заканчивается "}". Но, читая его и сохраняя в переменной, я сохранял его в объекте Array (как и в моем случае, могло быть более 1 объекта).
Следовательно, я добавил «[» в начале и «]» в конец моего файла JSON, чтобы преобразовать его в массив объектов, и он работал отлично без каких-либо ошибок.
источник
Как упоминалось выше, проблему решило бы следующее:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
Однако в моем случае провайдер выполнил сериализацию [0..1] или [0 .. *] скорее как ошибку, и я не мог принудительно исправить. С другой стороны, он не хотел влиять на мой строгий картограф во всех других случаях, которые требуют строгой проверки.
Итак, я сделал ГЛАВНЫЙ ХАК Jackson (который не следует копировать вообще ;-)), особенно потому, что у моего SingleOrListElement было только несколько свойств, которые нужно исправить:
источник
@JsonFormat (with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) частный список заказов <COrder>;
источник