Estou tentando postar um List
de objetos personalizados. Meu JSON no corpo da solicitação é este:
{
"collection": [
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
}
Código do lado do servidor que lida com a solicitação:
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();
}
}
Entidade 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() + "]";
}
}
Mas uma exceção é lançada:
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)
Em vez do documento JSON, você pode atualizar o objeto ObjectMapper como abaixo:
fonte
Isso funcionará:
O problema pode ocorrer quando você está tentando ler uma lista com um único elemento como um JsonArray em vez de um JsonNode ou vice-versa.
Como você não pode ter certeza se a lista retornada contém um único elemento (portanto, o json se parece com isso {...} ) ou vários elementos (e o json se parece com isso [{...}, {... }] ) - você terá que verificar em tempo de execução o tipo do elemento.
Deve ficar assim:
(Nota: neste exemplo de código, estou usando com.fasterxml.jackson)
fonte
Relacionado à resposta de Eugen, você pode resolver esse caso específico criando um objeto POJO de wrapper que contém a
Collection<COrder>
como sua variável de membro. Isso orientará adequadamente Jackson a colocar osCollection
dados reais dentro da variável de membro do POJO e produzir o JSON que você está procurando na solicitação da API.Exemplo:
Em seguida, defina o tipo de parâmetro
COrderRestService.postOrder()
como seu novoApiRequest
POJO do wrapper em vez deCollection<COrder>
.fonte
Encontrei esse mesmo problema hoje em dia e talvez mais alguns detalhes possam ser úteis para outra pessoa.
Eu estava procurando algumas diretrizes de segurança para APIs REST e cruzei um problema muito intrigante com matrizes json. Verifique o link para obter detalhes, mas, basicamente, você deve envolvê-los em um Objeto, como já vimos nesta pergunta.
Então, em vez de:
É aconselhável que sempre façamos:
Isso é bastante direto quando você faz um GET , mas pode lhe dar alguns problemas se, em vez disso, você estiver tentando POST / PUT o mesmo json.
No meu caso, eu tinha mais de um GET que era uma lista e mais de um POST / PUT que receberia o mesmo json.
Então, o que acabei fazendo foi usar um objeto Wrapper muito simples para uma Lista :
A serialização de minhas listas foi feita com um @ControllerAdvice :
Portanto, todas as listas e mapas foram agrupadas em um objeto de dados como abaixo:
A desserialização ainda era o padrão, apenas usando o Objeto Wrapper :
Foi isso! Espero que ajude alguém.
Nota: testado com SpringBoot 1.5.5.RELEASE .
fonte
Eu tive esse problema em uma API REST que foi criada usando a estrutura Spring. A adição de uma anotação @ResponseBody (para tornar a resposta JSON) a resolveu.
fonte
Normalmente, enfrentamos esse problema quando há um problema no mapeamento do nó JSON com o do objeto Java. Eu enfrentei o mesmo problema porque, na arrogância, o nó foi definido como da matriz Type e o objeto JSON estava tendo apenas um elemento; portanto, o sistema estava tendo dificuldade em mapear uma lista de elementos para uma matriz.
Em Swagger, o elemento foi definido como
Embora deva ser
E
TestNew
deve ser do tipo arrayfonte
fonte
O mesmo problema:
O que causou foi o seguinte:
No meu teste, defini propositadamente a solicitação como nula (sem conteúdo POST). Como mencionado anteriormente, a causa do OP foi a mesma, porque a solicitação não continha um JSON válido, portanto não pôde ser automaticamente identificada como uma solicitação de aplicativo / json, que era a limitação no servidor (
consumes = "application/json"
). Uma solicitação JSON válida seria. O que o corrigiu foi o preenchimento de uma entidade com corpo nulo e cabeçalhos json explicitamente.fonte
No meu caso, o erro estava sendo mostrado porque, quando eu estava lendo meu arquivo JSON usando a biblioteca Jackson, meu arquivo JSON continha apenas 1 objeto. Por isso, começou com "{" e terminou com "}". Mas enquanto lia e armazenava em uma variável, eu estava armazenando em um objeto Array (como no meu caso, poderia haver mais de 1 objeto).
Portanto, adicionei "[" no início e "]" no final do meu arquivo JSON para convertê-lo em uma matriz de objetos e funcionou perfeitamente sem nenhum erro.
fonte
Como mencionado acima, o seguinte resolveria o problema:
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
No entanto, no meu caso, o provedor fez essa serialização [0..1] ou [0 .. *] em vez de um bug e eu não pude aplicar a correção. Por outro lado, não queria impactar meu mapeador estrito para todos os outros casos que precisam ser validados estritamente.
Então eu fiz um Jackson NASTY HACK (que não deve ser copiado em geral ;-)), especialmente porque meu SingleOrListElement tinha apenas poucas propriedades para corrigir:
fonte
@JsonFormat (com = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) private List <COrder> pedidos;
fonte