Vraptor 3 - Serializar objetos em XML + Hibernate e JPA

Olá a todos,

estou com um problema ao serializar meus objetos através do VRaptor.

this.result.use(xml()).from(gerenciador.lista(usuario.getEmpresa()), "funcionarios").include("setor").serialize();

Se no JPA o relacionamento entre funcionario e setor for LAZY

o VRaptor serializa o objeto setor mas como um proxy do hibernate

Alguém sabe como resolver isso sem que seja definir o relacionamento como EAGER?

Desde já obrigado

vc vai ter que forçar o load da coleção…

ou chamando funcionario.getSetor();, ou se vc estiver usando HQL, vc pode forçar:

"from Funcionarios f join fetch f.setor where ...."

não testei essa query, mas é algo do tipo… talvez vc não precise da palavra fetch

Olá Lucas,

Está OK. Obrigado.

Nem precisei forçar o hibernate buscar no banco.

Fazendo os testes de serialização de objetos pelo XStream e Vraptor percebi um problema:

o XSTream usa getters e setters, correto!?

no entanto, fiz um teste assim:


	private String local = "atributo";

	public String getLocal() {
		return "get";
	}

e ele sempre retorna “atributo”. Ele não deveria usar o método getLocal?

desde já obrigado

por padrão o XStream usa fields… se vc quiser que ele use getters e setters vc precisa registrar o converter JavaBeanConverter:

xstream.registerConverter(new JavaBeanConverter());

a proxima versão do vrpator deve solucionar esse problema do lazy ^^

na verdade a que esta no snapshot já resolve…

só falta alguns detalhes pra ficar 100% =x

Lucas,

consegui fazer isso LOCAL, sem usar o Vraptor… quando uso o Vraptor nada é serializado…

eu já criei uma classe chamada CustomXMLSerialization para retornar o XStream com o registro do converter

xstream.registerConverter(new JavaBeanConverter(xstream.getMapper());

sabe oq pode estar acontecendo?

essa CustomXMLSerialization estende XStreamXMLSerialization? ela sobrescreve o método getXStream? ela está anotada com @Component?

Sim.

está tudo ok.

segue abaixo o código:

package br.com.originalsoftware.concrebase.controller;

import javax.servlet.http.HttpServletResponse;

import br.com.caelum.vraptor.interceptor.TypeNameExtractor;
import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.serialization.xstream.XStreamXMLSerialization;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.javabean.JavaBeanConverter;

@Component
public class CustomXMLSerialization extends XStreamXMLSerialization {

	public CustomXMLSerialization(HttpServletResponse response, TypeNameExtractor extractor) {
		super(response, extractor);
	}

	// delegate constructor
	@Override
	protected XStream getXStream() {
		XStream xstream = super.getXStream();
		xstream.registerConverter(new ConverterDate());
		xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()));
		return xstream;
	}
}

Esse component está sendo usado pelo Vraptor… o único problema é o JavaBeanConverter… quando eu registro ele… nada é serializado…

quando executo ele local funciona normalmente

pesquisei no google mas não encontrei uma solução…

cheguei a implementar o método canConverter e canHandle mas não mudou nada.

Lucas,

consegui.


		xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()) {
			public boolean canConvert(Class clazz) {
				return clazz.equals(Entrega.class);
			}
		});

Estava fazendo o canConvert retornar true quando o tipo era o tipo do retorno do atributo e não da classe.

Erro meu.

Obrigado pela ajuda.

O VRaptor serializa a proxy justo porque o XStream usa os atributos. Como ele acessa um atributo diretamente, se seu objeto é uma proxy (o session.load devolve proxy, apenas o .get faz uma requisicao direta sempre) ele vai serializar um monte de nulls e atributos especiias.

O Vitor e o Lavieri perceberam muito bem isso.

Vitor, pra ser sincero, eu havia tentado sua solução há algum tempo atrás, e tive o mesmo problema, tanto em testes com vraptor ou diretamente com o XStream. Em outras palavras, acho que o JavaBeanConverter nao esta mais funcionando como deveria.

Olá a todos,

havia esquecido de colocar a solução aqui.

A conclusão que eu cheguei é que o XStream não funciona corretamente quando você não especifica as classes que vão ser utilizadas pelo JavaBeanConverter mas, quando você especifica ele funciona direito.

Não fui atrás para saber o porque mas segue a solução abaixo:


@Component
public class CustomXMLSerialization extends XStreamXMLSerialization {

	public CustomXMLSerialization(HttpServletResponse response, TypeNameExtractor extractor) {
		super(response, extractor);
	}


	@Override
	protected XStream getXStream() {
		XStream xstream = super.getXStream();
		xstream.registerConverter(new ConverterDate());
		xstream.registerConverter(new JavaBeanConverter(xstream.getMapper()) {
			@SuppressWarnings("unchecked")
			public boolean canConvert(Class classe) {
				List<Class> classes = new ArrayList<Class>();
				classes.add(Betoneira.class);
				classes.add(Descarregamento.class);
				classes.add(Entrega.class);
				classes.add(Obra.class);
				classes.add(Posicionamento.class);
				classes.add(Rastreador.class);
				return classes.contains(classe);
			}
		});
		return xstream;
	}
}

Assim ele funciona corretamente e, não lendo a partir do field, ele não pode retornar o proxy do Hibernate.

Obrigado a todos

oi vitor

a versao 3.1.2, que deve sair na semana que vem, ja vem com uma correcao para o problema.

paulo

O que foi feito para corrigir o problema?

basicamente foi inicializar os proxies antes de serializar… o lavieri que fez =)

:oops:

Aos poucos a galera está conhecendo o projeto e logo começarão a vir muitas contribuições :smiley:

Alguem tentou o mesmo pra JSON?

Criei um CustomJSONSerialization semelhante ao do vitor.valerio, mas não consegui recuperar um objeto relacionado como EAGER :slight_smile:

vlw!

Eu estava fazendo errado. Nem precisou da classe.

Apenas adicionei o include no código abaixo e funcionou:

List&lt;Ad&gt; ads = this.adService.search(q);
this.result.use(Results.json()).from(ads).include("publisher").serialize();

Abs!