VRaptor + JSON

Boa tarde pessoal,

Estou com um problema meio estranho ao tentar consumir um JSON desta forma:

O método no controller:

   [code]@Consumes("application/json")
public void salvarTipoApoio(TipoApoio tipoApoio) {
	tipoApoioDao.salvar(tipoApoio);
}[/code]

A chamada Ajax:

    [code]var tipoApoio = {
		tipoApoio : {
			id : 22,
			nome : 'TESTE'
		}
};

alert(JSON.stringify(tipoApoio));

$.ajax({
    type : 'POST',
    contentType : 'application/json',
    url : '<%= request.getContextPath() %>/service/salvarTipoApoio',
    data : JSON.stringify(tipoApoio),
    dataType: 'json',
    beforeSend : function() {
        alert('antes de enviar');
    },
    success : function(txt) {
        alert('envio sucesso');
    },
    error : function(txt) {
        alert('erro envio');
    }
});[/code]

O erro é:

Caused by: java.lang.NullPointerException at br.com.caelum.vraptor.serialization.xstream.VRaptorClassMapper.shouldSerializeMember(VRaptorClassMapper.java:55) at com.thoughtworks.xstream.mapper.MapperWrapper.shouldSerializeMember(MapperWrapper.java:74) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:301) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:234) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) ... 53 more

O JSON está sendo montado corretamente, desta forma:

{“tipoApoio”:{“id”:22,“nome”:“TESTE”}}

Vi que outras pessoas tiveram o mesmo problema, porém não consegui resolver. Alguém poderia dar uma força?

Mais código de erro para ajudar:

[code]com.thoughtworks.xstream.converters.ConversionException: null : null
---- Debugging information ----
cause-exception : java.lang.NullPointerException
cause-message : null
class : br.gov.ce.sejus.sestap.model.TipoApoio
required-type : br.gov.ce.sejus.sestap.model.TipoApoio
converter-type : com.thoughtworks.xstream.converters.reflection.ReflectionConverter
line number : -1
version : null

at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79)[/code]

sua classe TipoApoio tá compatível com esse json? Dá pra postar ela ai?

Opa alias, com certeza, segue:

[code]@Entity
@Table(name = “tipo_apoio”, schema = “public”)
public class TipoApoio implements java.io.Serializable {

/**
 * 
 */
private static final long serialVersionUID = -3177706573195003152L;
private Integer id;
private String nome;

public TipoApoio() {
}

public TipoApoio(Integer id, String nome) {
	this.id = id;
	this.nome = nome;
}

@Id
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
	return this.id;
}

public void setId(Integer id) {
	this.id = id;
}

@Column(name = "nome", nullable = false, length = 100)
public String getNome() {
	return this.nome;
}

public void setNome(String nome) {
	this.nome = nome;
}

}[/code]

qual versao do VRaptor?

Estou usando a 3.4.1 (vraptor-3.4.1.jar)

tenta usar o 3.5.0, eu tinha corrigido esse erro.

Atualizei, porém o erro continuou, aí criei uma classe que implementa br.com.caelum.vraptor.deserialization.Deserializer, e o método deserialize está sendo chamado. Está é a solução correta?

faz essa sua classe que implementa deserializer estender JsonDeserializer, e veja se funciona.

Lucas, a classe ficou assim:

[code]import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;

import br.com.caelum.vraptor.deserialization.Deserializer;
import br.com.caelum.vraptor.deserialization.Deserializes;
import br.com.caelum.vraptor.deserialization.JsonDeserializer;
import br.com.caelum.vraptor.http.ParameterNameProvider;
import br.com.caelum.vraptor.interceptor.TypeNameExtractor;
import br.com.caelum.vraptor.resource.ResourceMethod;
import br.com.caelum.vraptor.serialization.xstream.XStreamBuilder;
import br.com.teste.model.TipoApoio;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

@Deserializes(“application/json”)
public class Helper extends JsonDeserializer implements Deserializer {

public Helper(ParameterNameProvider provider, TypeNameExtractor extractor,  
        XStreamBuilder builder) {  
    super(provider, extractor, builder);  
}  

@Override  
public Object[] deserialize(InputStream arg0, ResourceMethod arg1) {  
    Gson gson = new GsonBuilder().create();  
    BufferedReader reader = new BufferedReader(new InputStreamReader(arg0));  
    TipoApoio tipoApoio = gson.fromJson(reader, TipoApoio.class);  
    return null;  
}  

} [/code]

Estou retornando null pois realmente não faço ideia do que devo retornar. De qualquer forma o objeto TipoApoio está vindo com id e nome nulos do fromJson…

se vc vai modificar toda a deserialização não precisa fazer o extends, só o implements Deserializer já é o suficiente.

talvez se vc tirar o {‘tipoApoio’: } em volta do resto do JSON funcione (ou seja, deixar sem raiz)

vc pode também tentar usar a integração do GSON que já existe no VRaptor 3.5.0

registre o pacote br.com.caelum.vraptor.deserialization.gson no web.xml e remova o @deserializes desse seu deserializer.

Lucas, fiz assim mas não chega mais no Helper, dando essa exception:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'gsonDeserialization': Unsatisfied dependency expressed through constructor argument with index 1 of type [java.util.Collection]: : No matching bean of type [com.google.gson.JsonDeserializer] found for dependency [collection of com.google.gson.JsonDeserializer]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.google.gson.JsonDeserializer] found for dependency [collection of com.google.gson.JsonDeserializer]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:730) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:196) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory$2.getObject(AbstractBeanFactory.java:332) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.web.context.request.AbstractRequestAttributesScope.get(AbstractRequestAttributesScope.java:43) [spring-web-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:328) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBean(DefaultListableBeanFactory.java:274) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1106) [spring-context-3.1.2.RELEASE.jar:3.1.2.RELEASE] at br.com.caelum.vraptor.ioc.spring.SpringBasedContainer.instanceFor(SpringBasedContainer.java:86) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.deserialization.DefaultDeserializers.deserializerFor(DefaultDeserializers.java:46) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.interceptor.DeserializingInterceptor.intercept(DeserializingInterceptor.java:81) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.hydrustechnology.meubolao.util.Interceptador.intercept(Interceptador.java:39) [classes:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:67) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.interceptor.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:96) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:44) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:91) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58) [vraptor-3.5.0.jar:] at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:88) [vraptor-3.5.0.jar:] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:280) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.13.Final.jar:] at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:153) [jboss-as-web-7.1.1.Final.jar:7.1.1.Final] at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.13.Final.jar:] at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.13.Final.jar:] at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.13.Final.jar:] at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.13.Final.jar:] at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.13.Final.jar:] at java.lang.Thread.run(Unknown Source) [rt.jar:1.7.0_01] Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No matching bean of type [com.google.gson.JsonDeserializer] found for dependency [collection of com.google.gson.JsonDeserializer]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {} at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:952) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:779) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:735) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:795) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:723) [spring-beans-3.1.2.RELEASE.jar:3.1.2.RELEASE] ... 55 more

registra esse pacote tb:
br.com.caelum.vraptor.serialization.gson.adapters

Lucas, fiz isso mas o erro persistiu.

estranho…

cria essa classe no seu projeto então:

Lucas, aconteceu uma coisa estranha. Quando fui testar novamente com esta alteração que vc disse, consegui chegar até meu método salvarTipoApoio, só que estava vindo null, então voltei a raiz do json como estava antes e funcionou.

Será que foi algum pacote que registramos? Vou testar aqui.

Estranho, tenho as classes CalendarDeserializer.java e minha Helper:

[code]public class Helper implements Deserializer {

@Override
public Object[] deserialize(InputStream arg0, ResourceMethod arg1) {
	Gson gson = new GsonBuilder().create();
	BufferedReader reader = new BufferedReader(new InputStreamReader(arg0));
	TipoApoio tipoApoio = gson.fromJson(reader, TipoApoio.class);
	return null;
}

}[/code]

Se eu tirar qualquer uma dessas 2 classes, dá erro.

qual é o erro que acontece quando vc tira o helper?

Lucas, confusão minha, a falta do Helper não causa erro algum, funciona apenas adicionando a classe que vc pediu.

Só não entendi a necessidade de classe CalendarDeserializer.

Lucas, agradeço mais uma vez pela valiosa ajuda!

é que precisa ter alguma implementação de JsonDeserializer registrada… esse CalendarDeserializer foi lançado no pacote errado, por isso não foi registrado.