[RESOLVIDO] Erro de conversão no XStream usando vRaptor e RESTFulie  XML
Índice dos Fóruns » Frameworks e Bibliotecas brasileiros
Autor Mensagem
bland
JavaEvangelist

Membro desde: 10/12/2004 09:36:35
Mensagens: 330
Offline

Olá pessoal,

Estou tendo problemas para fazer um post tendo a seguinte estrutura de objetos:

- LoteDispensacaoDto


- LoteDispensacaoSolicitacaoDto


- ItemAprazamentoHorarioDto


- ItemAprazamentoDispensacaoDto


Vale ressaltar que a mesma estrutura de classes que tenho no meu cliente eu tenho no meu servidor; e busquei utilizar as anotações @XStreamAsAttribute e @XStreamImplicit para tentar resolver o meu problema, mas vi que não consegui.

A chamada para o meu serviço é:


Na minha classe do serviço ( anotado com @Resource ) eu tenho o método:


Esse objeto passado como parâmetro no método post possui toda a estrutura de objetos dentro dele preenchida. Fiz uma inspeção no XML que está sendo passado na requisição e vai o exemplo:


Então, aparentemente, está fazendo o processo corretamente, só que com um detalhe, não está considerando as listas dentro dos objetos. Ou seja, o objeto principal ( LoteDispensacaoDto ) possui uma lista do tipo LoteDispensacaoSolicitacaoDto, que também tem uma lista do tipo ItemAprazamentoHorarioDto, que, por sinal, também tem uma lista do tipo ItemAprazamentoDispensacaoDto.

Após a chamada do meu cliente, já no servidor, está sempre acontecendo este erro:

09/02/2011 12:01:35 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet default threw exception
com.thoughtworks.xstream.converters.ConversionException: itemAprazamentoHorario : itemAprazamentoHorario : itemAprazamentoHorario : itemAprazamentoHorario
---- Debugging information ----
message : itemAprazamentoHorario : itemAprazamentoHorario
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : itemAprazamentoHorario : itemAprazamentoHorario
class : br.com.scmba.ws.lancamento.item.conta.prontus.domain.entity.LoteDispensacaoDto
required-type : java.util.ArrayList
path : /loteDispensacao/loteDispensacaoSolicitacao/itemAprazamentoHorario
line number : 1
-------------------------------
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:89)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:63)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:76)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:246)
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:21
at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:162)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:82)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:63)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:76)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:60)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:137)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:33)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:923)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:909)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:861)
at br.com.caelum.vraptor.deserialization.XStreamXMLDeserializer.deserialize(XStreamXMLDeserializer.java:55)
at br.com.caelum.vraptor.interceptor.DeserializingInterceptor.intercept(DeserializingInterceptor.java:87)
at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:4
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:89)
at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23)
at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:5
at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:12
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
at java.lang.Thread.run(Thread.java:619)


A sensação que tenho é que ele não está conseguindo fazer a interpretação correta de uma lista dentro de outra lista, ou de qualquer lista dentro de um objeto passado por parâmetro.

Fazendo uma inspeção percebi que o XStream sempre cria um Map para fazer o de-para entre as classes anotadas com o tipo dela. E no meu exemplo ele esta associando, pelo que percebi, o tipo java.util.ArrayList a classe anotada LoteDispensacaoSolicitacaoDto ( por isso tentei utilizar a anotação @XStreamImplicit para sanar o problema ), pois essa classe está contida na classe LoteDispensacaoDto como um java.util.List.

Já busquei ver esse problema na internet mas não consegui encontrar a resolução do problema. Se puderem me ajudar...

Obrigado de antemão.

Abraço!

This message was edited 1 time. Last update was at 10/02/2011 09:21:05


http://www.twitter.com/almeidafabiano

Fabiano Almeida.
[MSN]
Lucas Cavalcanti
GUJ Hacker
[Avatar]

Membro desde: 08/07/2007 00:08:14
Mensagens: 6396
Offline

o problema é que o VRaptor não consegue ainda adivinhar quais classes vc vai usar do lado do servidor, pra poder
processar as annotations (vc precisa fazer isso explicitamente no XStream). Estamos vendo um jeito bom de fazer isso...

o jeito fácil de resolver é criando a classe:


--
Caelum
www.caelum.com.br

bland
JavaEvangelist

Membro desde: 10/12/2004 09:36:35
Mensagens: 330
Offline

Lucas,

Obrigado pela ajuda. Resolveu o meu problema. Tive que remover as anotações @XStreamAsAttribute e @XStreamImplicit das minhas classes que trafegam pelo serviço e adicionar esse CustomXStreamXMLDeserializer ao meu projeto.

Com essas mudanças eu consegui obter o objeto todo preenchido do lado do servidor, mas, como teste, eu criei no servidor um retorno como o abaixo:


E esse retorno está gerando no lado cliente o seguinte erro:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at br.com.caelum.restfulie.feature.FollowRedirects.process(FollowRedirects.java:27)
at br.com.caelum.restfulie.request.ResponseChain.next(ResponseChain.java:21)
at br.com.caelum.restfulie.request.RequestStack.process(RequestStack.java:3
at br.com.caelum.restfulie.request.RequestChain.next(RequestChain.java:20)
at br.com.caelum.restfulie.request.RequestStack.process(RequestStack.java:2
at br.com.caelum.restfulie.http.DefaultHttpRequest.sendPayload(DefaultHttpRequest.java:3
at br.com.caelum.restfulie.http.DefaultHttpRequest.post(DefaultHttpRequest.java:85)
at testes.Main.testWS(Main.java:153)
at testes.Main.main(Main.java:40)


Pelo que andei pesquisando e depurando, o erro acontece porque ele espera um path como parâmetro no header para poder fazer o redirect para uma URI. Como não passei nenhuma URI, está dando erro no seguinte ponto da classe FollowRedirects ( linha 27 ):

Ou seja, não existe qualquer teste para saber se existe ou não o "Location" no header, o que estaria levando ao erro acima.

Muito obrigado pela ajuda!

Abraço!

This message was edited 1 time. Last update was at 10/02/2011 09:18:51


http://www.twitter.com/almeidafabiano

Fabiano Almeida.
[MSN]
RafaelViana
GUJ Master

Membro desde: 23/03/2008 18:56:02
Mensagens: 1257
Localização: Venâncio Aires/RS
Offline

bland wrote:Lucas,

Obrigado pela ajuda. Resolveu o meu problema. Tive que remover as anotações @XStreamAsAttribute e @XStreamImplicit das minhas classes que trafegam pelo serviço e adicionar esse CustomXStreamXMLDeserializer ao meu projeto.

Com essas mudanças eu consegui obter o objeto todo preenchido do lado do servidor, mas, como teste, eu criei no servidor um retorno como o abaixo:


E esse retorno está gerando no lado cliente o seguinte erro:
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.ArrayList.RangeCheck(Unknown Source)
at java.util.ArrayList.get(Unknown Source)
at br.com.caelum.restfulie.feature.FollowRedirects.process(FollowRedirects.java:27)
at br.com.caelum.restfulie.request.ResponseChain.next(ResponseChain.java:21)
at br.com.caelum.restfulie.request.RequestStack.process(RequestStack.java:3
at br.com.caelum.restfulie.request.RequestChain.next(RequestChain.java:20)
at br.com.caelum.restfulie.request.RequestStack.process(RequestStack.java:2
at br.com.caelum.restfulie.http.DefaultHttpRequest.sendPayload(DefaultHttpRequest.java:3
at br.com.caelum.restfulie.http.DefaultHttpRequest.post(DefaultHttpRequest.java:85)
at testes.Main.testWS(Main.java:153)
at testes.Main.main(Main.java:40)


Pelo que andei pesquisando e depurando, o erro acontece porque ele espera um path como parâmetro no header para poder fazer o redirect para uma URI. Como não passei nenhuma URI, está dando erro no seguinte ponto da classe FollowRedirects ( linha 27 ):

Ou seja, não existe qualquer teste para saber se existe ou não o "Location" no header, o que estaria levando ao erro acima.

Muito obrigado pela ajuda!

Abraço!


Inclui essa verificação ao pegar o Location. Enviei um pull request para o projeto.

Rafael Rodrigues Viana
Estudando Java e Flex
Blog: http://www.cauirs.com.br/rafael/

"Any fool can write code that a computer can understand. Good programmers write code that humans can understand."
[Email] [MSN]
Lucas Cavalcanti
GUJ Hacker
[Avatar]

Membro desde: 08/07/2007 00:08:14
Mensagens: 6396
Offline

de qualquer forma, bland, quando vc retorna o status created vc deveria passar a location.

no VRaptor:



ou algo do tipo

--
Caelum
www.caelum.com.br

bland
JavaEvangelist

Membro desde: 10/12/2004 09:36:35
Mensagens: 330
Offline

Rafael, obrigado!

Lucas, porque deveria se existe um método chamado create que não tem a necessidade de passar parâmetros? Então esse método não deveria existir, é isso?

http://www.twitter.com/almeidafabiano

Fabiano Almeida.
[MSN]
Lucas Cavalcanti
GUJ Hacker
[Avatar]

Membro desde: 08/07/2007 00:08:14
Mensagens: 6396
Offline

existe pq vc pode setar o header location na mão:



principalmente pq vc pode adicionar várias locations.

a obrigatoriedade é por causa da especificação do 201 created no http

--
Caelum
www.caelum.com.br

Lucas Cavalcanti
GUJ Hacker
[Avatar]

Membro desde: 08/07/2007 00:08:14
Mensagens: 6396
Offline


10.2.2 201 Created

The request has been fulfilled and resulted in a new resource being created. The newly created resource can be referenced by the URI(s) returned in the entity of the response, with the most specific URI for the resource given by a Location header field. The response SHOULD include an entity containing a list of resource characteristics and location(s) from which the user or user agent can choose the one most appropriate. The entity format is specified by the media type given in the Content-Type header field. The origin server MUST create the resource before returning the 201 status code. If the action cannot be carried out immediately, the server SHOULD respond with 202 (Accepted) response instead.

A 201 response MAY contain an ETag response header field indicating the current value of the entity tag for the requested variant just created, see section 14.19.


http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html

This message was edited 1 time. Last update was at 10/02/2011 16:47:55


--
Caelum
www.caelum.com.br

Guilherme Silveira
Administrador

Membro desde: 14/08/2002 10:09:26
Mensagens: 1096
Localização: Sao Paulo
Offline

Oi pessoal,

Na verdade a spec diz "should" o que não significa "must". Se você não implementa o should não tem problema, você é parcialmente compliant. Se você implementa *todos* os should, você é compliant. Fica semi impossivel ser totalmente compliant sem colocar um proxy no meio para analisar todas as requisicoes (o proprio servidor pode ser parcially compliant).

Mas tenho sentido que vale a pena remover a opção do created sem Location sim. O problema é compatibilidade agora, remover tem que deixar claro o motivo.

Abraço!

-------------------------------------------------------
Guilherme Silveirahttp://blog.caelum.com.br
[Email] [WWW] [MSN]
 
Índice dos Fóruns » Frameworks e Bibliotecas brasileiros
Ir para:   
Powered by JForum 2.1.8 © JForum Team