VRaptor + Restfulie [Resolvido]

Chegou a necessidade de consumir os controllers que estão como restful no vraptor, se eu acesso a uri no navegador, me aparece o documento xml correto, agora se na hora em que vou consumir esse webservice esta dando esse erro:

Exception in thread "main" com.thoughtworks.xstream.mapper.CannotResolveClassException: categoriaveicular : categoriaveicular at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:71) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:86) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:96) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) at com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:52) at com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:31) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:136) 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:853) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:845) at br.com.caelum.restfulie.XStreamDeserializer.fromXml(XStreamDeserializer.java:32) at br.com.caelum.restfulie.http.DefaultResponse.getResource(DefaultResponse.java:61) at br.com.caelum.restfulie.EntryPointService.get(EntryPointService.java:107) at com.teste.principal.Principal.main(Principal.java:13)

Como o cliente será uma aplicação mobile, o client restifulie foi descartado.

A minha pergunta agora seria, como já existe aplicações usando SOAP como webservice, tem como através de SOAP fazer chamadas REST?
Dessa forma eu utilizo o Restifulie no server-side.

[quote=davisnog]Como o cliente será uma aplicação mobile, o client restifulie foi descartado.

A minha pergunta agora seria, como já existe aplicações usando SOAP como webservice, tem como através de SOAP fazer chamadas REST?
Dessa forma eu utilizo o Restifulie no server-side.[/quote]

Na sua pergunta eu não consigo entender a que conceitos você quer dizer sobre SOAP para REST, você quer empregar invocações para que especificação ? Na sua observação o Client Restifulie fora descarto “Implementação a que ?”.

Não sei como você está gerando o webservice, porém pelo erro é quando você esquece de colocar um alias para o bean. No caso o erro não parece ser no webservice, mas sim no seu cliente que consome o xml.

Quando você declara suas classes java precisa apontar quais atributos serão convertidos em qual classe. No caso o xstream usa ou o nome completo da classe ou então você precisa definir o alias manual, seja via código ou annotation.

Alex Basto seguinte, hoje eu gero os webservices com o restifulie, biblioteca disponibilizada pelo pessoal da caelum, junto com o vraptor, nesse caso os metodos de meus controllers são consumidos via webservice REST.

Mais, as aplicações mobile que temos hoje, consomem webservices no padrão SOAP, a minha pergunta era, seria possivel consumir os REST através de SOAP?

garcia-jj, as minhas classes model quanto a minha classe cliente, nos dois casos CategoriaVeicular, estão com alias do xstream.
Mais como eu havia dito, pra mobile ficou inviavel utilizar o restifulie como client, no caso será utilizado somente no server.

Aproveitando a oportunidade.

Hoje tenho minha classe model no projeto web, com as annotations do hibernate, por exemplo CategoriaVeicular.

No outro projeto mobile tem mesma classe, mais sem annotations, pois ela é utilizada para receber os dados do webservice.

Nesse caso eu tenho nos dois projetos com a mesma classe CategoriaVeicular, a diferença é que no projeto web eu tenho as dependências do hibernate e no mobile não.

Minha pergunta seria: Tem alguma sugestão para que eu possa gerar um jar das classes model e disponibilizar para as duas aplicações, nesse caso as alterações seriam todas feitas no projeto web, e dessa forma qualquer alteração necessária seria feita num unico projeto.

Hmm, você pode nos mostrar como está seu cliente? Apenas a classe que consome.

Codigo no client, essa é uma aplicação console que esta consumindo o webservice.

[code]@XStreamAlias(“categoriaveicular”)
public class CategoriaVeicular {

private int codigo; 
private String descricao;
private Situacao situacao;

//gets e sets removidos
}
public class PrincipalTeste{
public static void main(String[] args) throws URISyntaxException{
CategoriaVeicular categoriaVeicular = Restfulie.resource(“http://localhost:8080/categoriaveicular/1”).get();
}
}

[/code]

No servidor a diferença é que tem as annotations do hibernate.

[quote=davisnog]Aproveitando a oportunidade.

Hoje tenho minha classe model no projeto web, com as annotations do hibernate, por exemplo CategoriaVeicular.

No outro projeto mobile tem mesma classe, mais sem annotations, pois ela é utilizada para receber os dados do webservice.

Nesse caso eu tenho nos dois projetos com a mesma classe CategoriaVeicular, a diferença é que no projeto web eu tenho as dependências do hibernate e no mobile não.

Minha pergunta seria: Tem alguma sugestão para que eu possa gerar um jar das classes model e disponibilizar para as duas aplicações, nesse caso as alterações seriam todas feitas no projeto web, e dessa forma qualquer alteração necessária seria feita num unico projeto.[/quote]

Davi, você pode usar algum gerador que sempre que você altere a classe ele crie para você a classe do projeto mobile. Mas minha sugestão é fazer manual mesmo, pois essa coisa de classe persistente ser espelho de classe de transferencia de dados não me parece bom. Obvio que isso varia de projeto a projeto, mas não curto muito (minha opinião).

Penso assim porque nem sempre você tem as classes exatamente iguais. Uma coisa é a sua estrutura de tabelas e outra é o que você precisa trafegar e exibir para o cliente.

Então… mesmo definindo os Alias via anotações, vc precisa registrar as classes no XStream… tem algo como xstream.readAnnotations(CategoriaVeicular.class) ou coisa do tipo…

qto a pergunta se tem como consumir REST via SOAP, acho que não dá… o formato das msgs soap é bem diferente (tem cabeçalho, corpo e tal)

[quote=davisnog]Codigo no client, essa é uma aplicação console que esta consumindo o webservice.
[…]
No servidor a diferença é que tem as annotations do hibernate.[/quote]

Davi, me parece normal sua classe mesmo. Mande o envelope do XML para comparar?

Abraços

Não, não dá mesmo. Rest além de você possuir aqueles estados que o SOAP também tem, no rest você não possui um contrato formal, portanto seu XML é assim como você quiser, por exemplo:

<caelum-projetos> <projeto name="vraptor3" /> <projeto name="restfulie" /> </caelum-projetos>

Já no SOAP você tem contratos fortes entre o serviço e o consumidor. Todo SOAP possui um WSDL que define esse contrato e garante que todo mundo saiba como consumir esse webservice. O webservice possui um envelope com uma série de informações além do seu próprio XML de retorno.

Bom a classe envelope se eu entedi é essa:

[code]@Component
@RequestScoped
public class XmlSerializer extends RestfulSerialization {

public XmlSerializer(HttpServletResponse response,
		TypeNameExtractor extractor, Restfulie restfulie,
		Configuration config) {
	super(response, extractor, restfulie, config);
}

@Override
protected XStream getXStream() {
	XStream instance = super.getXStream();
	instance.processAnnotations(CategoriaVeicular.class);
	return instance;
}

}[/code]

Bom dia Davi, Garcia,

Realmente a exception parece não estar usando o XStream com a configuração que voce citou. Mas como no cliente não poderá usar o restfulie por ser celular, deixamos de lado. Se aparecer o problema novamente, poste o código do cliente por aqui?

Sobre SOAP consumir REST, como as mensagens em REST geradas pelo serializador não está envelopada em soap por padrão, não funcionará.
Mas a questão da arquitetura REST não possuir um contrato formal é um pouco diferente. Você pode - e muitos dizem que deve - criar xsd’s ou utilizar o schematron para fazer a validação de sua estrutura xml e REST não te proibe de faze-lo, basta adicionar o cabeçalho com link para seu schema:

<!-- cabecalho para seu xsd aqui -->
 <caelum-projetos>  
     <projeto name="vraptor3" />  
     <projeto name="restfulie" />  
 </caelum-projetos>  

Tem um post aqui sobre o assuntO: http://guilhermesilveira.wordpress.com/2009/12/08/hypermedia-making-it-easier-to-create-dynamic-contracts/

O REST também possui as informações (metadados) que o soap define em diversos momentos, mas utiliza cabeçalhos http (o protocolo em si) para passar parte dessas informações.

Na parte de criar uma classe anotada/não anotada para ser usada nos dois lugares, algumas pessoas vão recomendar não usar a mesma classe mesmo: se você disponibiliza a mesma classe para os dois lados, você aumenta o acoplamento entre os dois lados. Permitindo cada lado ter uma representação diferente (com os campos que interessa para cada um) diminui o acoplamento, mas isso só faz sentido se você for disponibilizar para outros clientes diferentes.

Abraço

ainda sobre a classe anotada/não anotada. Somente o projeto web poderá fazer alterações, o mobile somente vai ter essas classes para receber os dados do webservice.

Como o Garcia falou de um gerador, alguem conhece algum?

Fazendo uns testes aqui, lembrei que posso utilizar Results.representation(), mais dai eu não consegui utilizar as url como eu usaria se não precisasse passar _format=xml, antes eu fazia assim http://localhost:8080/Testes/categoriaveicular/1, com eu preciso passar o formato eu tenho que fazer assim http://localhost:8080/Testes/categoriaveicular.buscar?_format=xml&categoriaVeicular.codigo=1.

Tem uma forma de fazer isso usando o metodo padrão de url?

Eu pensei em algo assim:

http://localhost:8080/Testes/categoria-veicular/formato/parametro, no caso se não tiver o formato seria html normal.

[quote=davisnog]Fazendo uns testes aqui, lembrei que posso utilizar Results.representation(), mais dai eu não consegui utilizar as url como eu usaria se não precisasse passar _format=xml, antes eu fazia assim http://localhost:8080/Testes/categoriaveicular/1, com eu preciso passar o formato eu tenho que fazer assim http://localhost:8080/Testes/categoriaveicular.buscar?_format=xml&categoriaVeicular.codigo=1.

Tem uma forma de fazer isso usando o metodo padrão de url?

Eu pensei em algo assim:

http://localhost:8080/Testes/categoria-veicular/formato/parametro, no caso se não tiver o formato seria html normal.[/quote]

Só fica difícil chamar isso de REST depois.

Falando nisso, qual o ganho em adicionar o framework restfulie ao vraptor neste caso, com tantas limitações no lado cliente?

O Restfulie seria utilizado somente do server, o ganho seria com o controle de transação no rest, mais eu acho que isso já é feito pelo proprio vraptor, sem a necessidade do restfulie.

O controle de transacao dentro de uma requisicao realmente é interno e nao depende do Restfulie.
A vantagem do restfulie entra na parte do hypermedia… se nao for necessario ele, so o representation deve ser suficiente!

Abraco