VRaptor 3 - Problema com a serialização de resultados JSON e XML

15 respostas
marciobarroso

Estou modelando alguns serviços utilizando VRaptor como controlador MVC.

Todas os resultados dos serviços serão JSON ou XML.

Eu modelei um objeto para ser trafegado para os retornos.

Basicamente seria algo assim:

Criei uma classe abstrata que já tem alguns métodos genéricos. Todos estes métodos tem uma ação default que seria informar se foi executado com sucesso ou com erro e uma mensagem.

Existem outros métodos que além destas duas mensagens ( status de execução e mensagem ), eles retornam também um objeto.

Por exemplo:

Um método de list, retorna um objeto do tipo List<?>.

Um método get, retorna um objeto complexo qualquer.

Então eu criei uma classe para ser meu retorno default:

class RequestResult implements Serializable {
		
		private static final long serialVersionUID = 1282868667927366619L;
		
		private ResultType type;
		private String message;
		private Object object;
		
		public ResultType getType() {
			return this.type;
		}
		public void setType(ResultType type) {
			this.type = type;
		}
		public String getMessage() {
			return this.message;
		}
		public void setMessage(String message) {
			this.message = message;
		}
		public Object getObject() {
			return this.object;
		}
		public void setObject(Object object) {
			this.object = object;
		}
	}

então, hora eu seto somente o type ( SUCCESS ou ERROR ) e o message, hora eu seto além destes dois campos, o campo object com o objeto carregado pela classe de business ou então uma lista.

Na hora de renderizar a tela, só esta sendo carregado o type e a message. O objeto complexo não esta sendo adicionado ao XML ou JSON.

eu criei um método que executo depois de cada execução de métodos desta classe abstrata:

protected void afterExecution(ResultType result, String message, Object obj) throws ControllerException {
		RequestResult rr = new RequestResult();
		rr.setType(result);
		rr.setMessage(message);
		rr.setObject(obj);
		
		if( this.returnType.equals(ReturnType.JSON) ) {
			this.result.use(Results.json()).from(rr, "result").serialize();
		} else if( this.returnType.equals(ReturnType.XML) ) {
			this.result.use(Results.xml()).from(rr, "result").serialize();
		} else {
			throw new NullPointerException("Return type not found for Controller implementation");
		}
	}

Alguma sugestão do que devo fazer para resolver este problema??

[]'s

15 Respostas

Lucas_Cavalcanti

o vraptor só serializa os atributos simples, por padrão… se vc quiser incluir o objeto vc precisa dar um .include(“object”) antes do .serialize()

marciobarroso

Lucas,

Já tentei fazer isso … acho que estou tendo problemas porque estou usando tipos genéricos nesta classe … Eu lí algo que você escreveu que diz que o VRaptor precisa conhecer a implementação para conseguir serializar.

É isso mesmo??

marciobarroso

Lucas,

Tentei novamente fazer como sugeriu.

A classe ficou assim:

public class RequestResult&lt;T&gt; implements Serializable {

	private static final long serialVersionUID = -7516397213108095485L;

	private ResultType type;
	private String message;
	private T entity;
	private List&lt;T&gt; entities;
	
	public ResultType getType() {
		return this.type;
	}
	public void setType(ResultType type) {
		this.type = type;
	}
	public String getMessage() {
		return this.message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public T getEntity() {
		return this.entity;
	}
	public void setEntity(T entity) {
		this.entity = entity;
	}
	public List&lt;T&gt; getEntities() {
		return this.entities;
	}
	public void setEntities(List&lt;T&gt; entities) {
		this.entities = entities;
	}
}

Após as execuções estou fazendo o seguinte:

protected void afterExecution(ResultType result, String message, List&lt;T&gt; entities) throws ControllerException {
		RequestResult&lt;T&gt; rr = new RequestResult&lt;T&gt;();
		rr.setType(result);
		rr.setMessage(message);
		rr.setEntities(entities);
		
		if( this.returnType.equals(ReturnType.JSON) ) {
			this.result.use(Results.json()).from(rr, this.getUrlBasedKey()).include("entities").serialize();
		} else if( this.returnType.equals(ReturnType.XML) ) {
			this.result.use(Results.xml()).from(rr, this.getUrlBasedKey()).include("entities").serialize();
		} else {
			throw new NullPointerException("Return type not found for Controller implementation");
		}
	}

e esta gerando esta exceção:

br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
	at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:86)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:69)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:90)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:42)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.InterceptorListPriorToExecutionExtractor.intercept(InterceptorListPriorToExecutionExtractor.java:44)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:81)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:67)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:53)
	at br.com.caelum.vraptor.core.DefaultRequestExecution.execute(DefaultRequestExecution.java:70)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:56)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
	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:240)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:164)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:562)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:395)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:250)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:188)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:166)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
	at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
	at br.com.caelum.vraptor.serialization.xstream.XStreamSerializer.getActualType(XStreamSerializer.java:208)
	at br.com.caelum.vraptor.serialization.xstream.XStreamSerializer.include(XStreamSerializer.java:187)
	at com.marciob.apps.entity.system.controller.AbstractController.afterExecution(AbstractController.java:153)
	at com.marciob.apps.entity.system.controller.AbstractController.add(AbstractController.java:52)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:57)
	... 47 more

Pela exceção dá para ter idéia que o problema é mesmo o que eu falei … o VRaptor precisa conhecer a implementação para serializar, ou em outras palavras, com o generics não vai rolar.

Tem alguma outra forma de implementar isso? Talvez criando uma implementação custom do Serialization??

[]'s

Lucas_Cavalcanti

acho que isso já foi corrigido… tenta usar esse snapshot:
https://oss.sonatype.org/content/repositories/snapshots/br/com/caelum/vraptor/3.4.0-SNAPSHOT/vraptor-3.4.0-20110915.225054-8.jar

marciobarroso

Lucas,

Sabe se existe em algum lugar um POM com as dependências do VRaptor 3.4.0-SNAPSHOT ???

Coloquei esta versão, mas esta dando problema nas dependências … esta faltando um monte de dependências que não tinha nas versões anteriores.

[]'s

Lucas_Cavalcanti

quais dependências estão faltando, marcio?

marciobarroso

Lucas,

Utilizando o POM que você me passou, consegui acertar todas as dependências do projeto, no entanto, a exceção ainda persiste.

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
	br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:96)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:87)
	br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23)
	br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
	br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)

root cause

java.lang.ClassCastException: sun.reflect.generics.reflectiveObjects.TypeVariableImpl cannot be cast to java.lang.Class
	br.com.caelum.vraptor.serialization.xstream.XStreamSerializer.getActualType(XStreamSerializer.java:237)
	br.com.caelum.vraptor.serialization.xstream.XStreamSerializer.include(XStreamSerializer.java:208)
	com.marciob.apps.entity.system.controller.AbstractController.afterExecution(AbstractController.java:153)
	com.marciob.apps.entity.system.controller.AbstractController.add(AbstractController.java:52)
	sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	java.lang.reflect.Method.invoke(Method.java:597)
	br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:61)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:87)
	br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23)
	br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
	br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)

note The full stack trace of the root cause is available in the Apache Tomcat/7.0.12 logs.

Você consegue imaginar outra forma para contornar este problema?

Será que eu não vou conseguir utilizar este objeto genérico para dar o retorno dos meus serviços REST?!?

[]'s

Lucas_Cavalcanti

marcio, quais dependencias estavam faltando?

marciobarroso

Estavam faltando a scannotation e guava ( google.collection )

Lucas_Cavalcanti

não quer corrigir lá no VRaptor e mandar um pull request por favor?

ou o pom mais novo já está certo?

Lucas_Cavalcanti

em todo caso, essa exception já deveria estar corrigida no último snapshot do vraptor

marciobarroso

Lucas Cavalcanti:
não quer corrigir lá no VRaptor e mandar um pull request por favor?

ou o pom mais novo já está certo?

O pom que você me passou já tem estas dependências =)

Sobre a exceção, eu baixei o snapshot que você me passou … e o problema ainda persiste. Acabei removendo o generics do meu objeto para contornar o problema.

[]'s

Lucas_Cavalcanti

qual é o caso em que deu problemas? posta aí as classes (com generics) que vc mandou serializar por favor?

marciobarroso

a classe é essa:

public class RequestResult<T> implements Serializable {

	private static final long serialVersionUID = -7516397213108095485L;

	private ResultType type;
	private String message;
	private T entity;
	private List<T> entities;
	
	public ResultType getType() {
		return this.type;
	}
	public void setType(ResultType type) {
		this.type = type;
	}
	public String getMessage() {
		return this.message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
	public T getEntity() {
		return this.entity;
	}
	public void setEntity(T entity) {
		this.entity = entity;
	}
	public List<T> getEntities() {
		return this.entities;
	}
	public void setEntities(List<T> entities) {
		this.entities = entities;
	}
}

Eu fiz uma classe abstrata genérica que trata minhas respostas e sempre coloca uma instancia deste objeto como resultado JSON ou XML. Só que com o generics não funciona.

[]'s

Lucas_Cavalcanti

ok, vou tentar fazer um teste para simular esse bug.

abre uma issue por favor?

Criado 15 de setembro de 2011
Ultima resposta 26 de set. de 2011
Respostas 15
Participantes 2