Vraptor 3 + JSON

26 respostas
ViniciusNaka

Boa tarde galera…

estou com o seguinte erro ao tentar serializar um objeto…

public void listarFuncConsolidado(){
		result.include("departamentoList", departamentoDAO.listar());
		List<PontuacaoFunc> pontuados = pontuacaoFuncDAO.listarConsolidado();		
		result.use(json()).withoutRoot().from(pontuados).include("colaborador").serialize(); //quando passa por aqui consta o erro abaixo
	}
Caused by: java.lang.IllegalArgumentException: Field path colaborador doesnt exist

at br.com.caelum.vraptor.serialization.xstream.XStreamSerializer.include(XStreamSerializer.java:207)

at voxage.com.br.controllers.PontuacaoController.listarFuncConsolidado(PontuacaoController.java:85)

at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.lang.reflect.Method.invoke(Unknown Source)

at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:61) 42 more

minha classe PontuacaoFunc para auxilio…

@Entity
@Table(name="pontuacao_func")
public class PontuacaoFunc implements Serializable{

	private static final long serialVersionUID = 3214100040938150076L;

	@Id
	@GeneratedValue
	@Column(name="id_pont_func")
	private Integer idPontuacaoFunc;
	
	@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinColumn(name="id_tipo_pontuacao", referencedColumnName="id_tipo_pontuacao")
	private TipoPontuacao tipoPontuacao;
	
	@Column(name="motivo")
	private String motivo;
	
	@Column(name="valor")
	private Integer valor;
	
	@Column(name="data_pont")
	private Date data;
	
	@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinColumn(name="id_func_pont", referencedColumnName="id_func")
	private Funcionario colaborador;
	
	@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
	@JoinColumn(name="id_gestor_pont", referencedColumnName="id_func")
	private Funcionario gestor;

        // getters e setters

desde já agradeço a ajuda.

abs

26 Respostas

Lucas_Cavalcanti

só pra entender o erro, a lista que vai ser serializada está nula? vazia?

mascjunior

Boa Noite Vinicius,

conseguiu resolver o seu erro?

estou com o mesmo problema.

att,

ViniciusNaka

E ai pessoal, eu cometi uma gafe :frowning: hehe… me desculpem! :oops:

mascjunior, no meu caso eu revi debugando que no meu DAO estava retornando atributos específicos e nao o objeto…

public void listarFuncConsolidado(){  
        result.include("departamentoList", departamentoDAO.listar());  
        List<PontuacaoFunc> pontuados = pontuacaoFuncDAO.listarConsolidado();  // esse metodo aqui    
        result.use(json()).withoutRoot().from(pontuados).include("colaborador").serialize();
    }

por isso q constava aquele erro hehe

vc conseguiu resolver?

abs

gabriel.mancini

cara o meu aki funciona bem

Objeto ob = repository.getObjeto(id);

result
			.use(json())
			.withoutRoot()
			.from(ob)
			.exclude("objRecursivo", "prop.objR")			
			.recursive()
			.serialize();

agora o meu problema esta sendo o contrario
estou tentando enviar via:
AJAX
usando um POST
um dado em JSON
minha action eh executada mais não eh feito a deserialização

alguem tem alguma ideia?

eu vi uma thred aki no guj que fala algo assim
http://www.guj.com.br/java/197235-vraptor3-serializedeserialize-listas-com-xstream

mais não entendi onde eu coloco o codigo de deserializacao
eu tenho um

public class CustomJSONSerialization extends XStreamJSONSerialization

teria algo para deserializar json?

Lucas_Cavalcanti

que erro dá?

gabriel.mancini

então tentei realizar o PUT (ou POST, ja tentei os 2), e a execução ate chama a action mais o parametro chega null

@Transactional
	@Put("/templates")	
	public void update(EtiquetaTemplate etiquetaTemplate) {		
		
		validator.validate(etiquetaTemplate);
		validator.onErrorUsePageOf(this).edit(etiquetaTemplate.getId());

		etiquetaTemplate.getId().setVersao(etiquetaTemplate.getId().getVersao()+1);
		repository.create(etiquetaTemplate);

		result.redirectTo(this).index();
	}
@Transactional
	@Put("/templates.json")	
	public void update(String etiquetaTemplate) {		
		System.out.print(etiquetaTemplate);

		result.redirectTo(this).index();
	}
Lucas_Cavalcanti

ah tah, se vc quer que o VRaptor deserialize algo que veio por json (ou xml) vc precisa anotar o método do controller com @Consumes:

@Consumes("application/json") // ou sem o parâmetro
@Put("/templates")    
public void update(EtiquetaTemplate etiquetaTemplate) {       

...
}

senão o vraptor só tenta popular com os dados do formulário (parâmetros do request)

gabriel.mancini

Ahh Legal Lucas,

mais e se eu estiver utilizando o Results.representation() ?
sendo assim a action deveria verificar o requestHeader antes de saber como tratar o parametro enviado

como isso funcionaria??

Lucas_Cavalcanti

uma coisa é o content-type da requisição (que o VRaptor usa para deserializar) e outra é o header Accept (que o VRaptor usa no representation, para serializar).

se vc está usando um cliente http para se comunicar com o VRaptor, vc precisa setar tanto o header Content-type quanto o Accept.

de qqer forma vc não precisa mexer com esses headers na mão, o VRaptor já faz isso

gabriel.mancini

acho q não entendi direito,

por exemplo na action Show se eu enviar um:
get normal (pelo browser) ele renderiza a view correspondente
get getJSON (usando jquery) ele renderiza um json

@Transactional
	@Get
	@Path(value="/templates/{templatepk.nome}", priority=Path.LOWEST)
	public void show(EtiquetaTemplatePK templatepk) {
		EtiquetaTemplate ed = repository.getTemplateByNome(templatepk.getNome());

		result
			.use(Results.representation())			
			.from(ed)
			.exclude("usuarioCriacao", "regioes.template")			
			.recursive()
			.serialize();
	}

agora quero fazer algo assim no update, então caso eu envio o put via form request ele identifica
mais se eu envia usando um putJSON ele não deserializa pro objeto

@Transactional
	@Put("/templates")	
	@Consumes  
	public void update(EtiquetaTemplate etiquetaTemplate) {		
		
		validator.validate(etiquetaTemplate);
		validator.onErrorUsePageOf(this).edit(etiquetaTemplate.getId());

		etiquetaTemplate.getId().setVersao(etiquetaTemplate.getId().getVersao()+1);
		repository.create(etiquetaTemplate);

		result.redirectTo(this).index();
	}

ele da um erro:

[list]Unable to handle media type [application/x-www-form-urlencoded]: no deserializer found.[/list]

PS: eu sei q o metodo putJSON não existe no jquery mais eu o extendi

function _ajax_request(url, data, callback, type, method) {
	
	if (jQuery.isFunction(data)) {
		method = method || type;
		type = type || callback;
		callback = data;
		data = undefined;
	}
	
	return jQuery.ajax({
		type: method
		, url: url
		, data: data
		, success: callback
		, dataType: type
	});
}

jQuery.extend({
	put: function(url, data, callback, type) {
		return _ajax_request(url, data, callback, type, 'PUT');
	}
	, delete_: function(url, data, callback, type) {
		return _ajax_request(url, data, callback, type, 'DELETE');
	}
});

jQuery.extend({
	postJSON: function(url, data, callback) {
		return jQuery.post(url, data, callback, 'json');
	}
	, putJSON: function(url, data, callback) {
		return jQuery.put(url, data, callback, 'json');
	}
	, deleteJSON: function(url, data, callback) {
		return jQuery.delete_(url, data, callback, 'json');
	}
});

aki [url]http://gabrielmancini.blogspot.com/2011/05/rest-jquery-ajax-json.html[/url] eu explico melhor como isso funciona

Lucas_Cavalcanti

o dataType é o que vc espera receber, não é o que ele vai mandar… ou seja, é o Accept, não o Content-Type.

por padrão ele manda o data como www-formurlencoded, que o VRaptor trata como parametro da request mesmo…

faz um teste, olhe no firebug quais são os headers da requisição

gabriel.mancini

desculpa lucas não entendi.

vc entendeu qual eh minha intenção?

Lucas_Cavalcanti

entendi, o problema é o tipo e o formato de dados que o jquery tah mandando pro VRaptor…

vc tem o firebug instalado no seu firefox?

consegue ver qual é o corpo e os headers da sua requisição que usa o putJSON?

gabriel.mancini

Cabeçalhos de Resposta Server Apache-Coyote/1.1 Content-Type text/html;charset=utf-8 Content-Length 1312 Date Thu, 19 May 2011 17:16:22 GMT Cabeçalhos de Solicitação Host localhost:8080 User-Agent Mozilla/5.0 (Windows NT 5.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1 Accept application/json, text/javascript, */*; q=0.01 Accept-Language pt-br Accept-Encoding gzip, deflate Accept-Charset ISO-8859-1,utf-8;q=0.7,*;q=0.7 Keep-Alive 115 Connection keep-alive Content-Type application/x-www-form-urlencoded; charset=UTF-8 X-Requested-With XMLHttpRequest Referer http://localhost:8080/etiquetas-interface/templates/Template%201/edit Content-Length 150 Cookie JSESSIONID=120F6F9B83158575A2C8099F72449FED

Lucas_Cavalcanti

o cabeçalho da requisição:
Content-Type application/x-www-form-urlencoded; charset=UTF-8

ou seja, o VRaptor vai tentar tratar o que veio como form parameter (o funcionamento normal)…

dê uma olhada nisso:
http://api.jquery.com/jQuery.ajax/

específicamente as options contentType, data e proccessData

gabriel.mancini

Legal corrigido.

so uma questão como eu seto as particularidades de deserialização
por ex: o erro exibe um problema de cast.

adicionei a dependencia do com.thoughtworks.xstream.mapper.CannotResolveClassException: etiquetaTemplate.id : etiquetaTemplate.id com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.DynamicProxyMapper.realClass(DynamicProxyMapper.java:71) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.PackageAliasingMapper.realClass(PackageAliasingMapper.java:88) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.ClassAliasingMapper.realClass(ClassAliasingMapper.java:86) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.ArrayMapper.realClass(ArrayMapper.java:96) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.MapperWrapper.realClass(MapperWrapper.java:38) com.thoughtworks.xstream.mapper.CachingMapper.realClass(CachingMapper.java:52) com.thoughtworks.xstream.core.util.HierarchicalStreams.readClassType(HierarchicalStreams.java:29) com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:136) com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:33) com.thoughtworks.xstream.XStream.unmarshal(XStream.java:923) com.thoughtworks.xstream.XStream.unmarshal(XStream.java:909) com.thoughtworks.xstream.XStream.fromXML(XStream.java:861) br.com.caelum.vraptor.deserialization.JsonDeserializer.deserialize(JsonDeserializer.java:39) br.com.caelum.vraptor.interceptor.DeserializingInterceptor.intercept(DeserializingInterceptor.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.ParametersInstantiatorInterceptor.intercept(ParametersInstantiatorInterceptor.java:89) br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:59) br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54) br.com.abril.etiquetasinterface.interceptor.AuthorizationInterceptor.intercept(AuthorizationInterceptor.java:52) 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.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56) 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.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.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.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) com.opensymphony.sitemesh.webapp.SiteMeshFilter.obtainContent(SiteMeshFilter.java:129) com.opensymphony.sitemesh.webapp.SiteMeshFilter.doFilter(SiteMeshFilter.java:77)

Lucas_Cavalcanti

qual é o json que o browser gerou mesmo? (no firebug tem um lugar que mostra o corpo da requisição)

gabriel.mancini
{"id":{"nome":"Template 1","versao":10},"descricao":"Descricao do Template","dataCriacao": "2011-05-03 16 =55 =01.0","margemSuperior":10,"margemInferior":10,"margemDireita":8.5,"margemEsquerda":8.5,"espacamentoHorizontal":0,"espacamentoVertical":0,"larguraFormulario":297,"alturaFormulario":210,"larguraEtiqueta":70,"alturaEtiqueta":38,"regioes":[]}

não seria mais simples ter uma classe de deserialização tipo a de serialização

import java.io.Writer;
import java.util.Collection;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;


import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.converters.collections.CollectionConverter;
import com.thoughtworks.xstream.converters.collections.MapConverter;
import com.thoughtworks.xstream.converters.enums.EnumConverter;
import com.thoughtworks.xstream.converters.javabean.JavaBeanConverter;
import com.thoughtworks.xstream.io.HierarchicalStreamDriver;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;

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

@Component
public class CustomJSONSerialization extends XStreamJSONSerialization {
    //delegate constructor
    
    public CustomJSONSerialization(HttpServletResponse response,
			TypeNameExtractor extractor, ProxyInitializer initializer) {
		super(response, extractor, initializer);
		// TODO Auto-generated constructor stub
	}
    
    @Override  
    protected HierarchicalStreamDriver getHierarchicalStreamDriver() {  
        return new JsonHierarchicalStreamDriver() {  
             public HierarchicalStreamWriter createWriter(Writer writer) {  
                   return new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE);  
             }  
        };  
    }  
    
	@Override
    protected XStream getXStream() {
        XStream xStream = super.getXStream();
        xStream.registerConverter(new EnumConverter());
        xStream.registerConverter(new CollectionConverter(xStream.getMapper()) {
	        @Override
	        @SuppressWarnings("rawtypes")
	        public boolean canConvert(Class type) {
	            return Collection.class.isAssignableFrom(type);
	        }
	    });
        
        xStream.registerConverter(new MapConverter(xStream.getMapper()) {
            @Override
            @SuppressWarnings("rawtypes")
            public boolean canConvert(Class type) {
                return Map.class.isAssignableFrom(type);
            }
        });

        return xStream;
    }
}
Lucas_Cavalcanti

esse é o de resposta ou o de requisição?

gabriel.mancini

é daquele request q eu mandei o console do firebug

Lucas_Cavalcanti

dá pra ter de deserialização, basta implementar Deserializer e anotar com Deserializes

@Deserializes({"application/json", "text/json"})
public class JSONDeserializer implements Deserializer {
    //...
}
Lucas_Cavalcanti

o problema maior é que deserializar json é meio difícil de fazer genericamente, pois tem menos nomes.

deserializar xml é um pouco mais fácil

gabriel.mancini

isso não adiantaria?

import br.com.abril.etiquetasinterface.models.EtiquetaTemplate;
import br.com.caelum.vraptor.deserialization.XStreamXMLDeserializer;
import br.com.caelum.vraptor.http.ParameterNameProvider;
import br.com.caelum.vraptor.ioc.Component;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;

@Component
public class CustomJSONDeserialization extends XStreamXMLDeserializer {
    //delegate constructor
        
    public CustomJSONDeserialization(ParameterNameProvider provider) {
		super(provider);
		// TODO Auto-generated constructor stub
	}
    
	@Override
    protected XStream getXStream() {
		
		XStream xStream = new XStream(new JettisonMappedXmlDriver());
	
		xStream.alias("etiquetaTemplate", EtiquetaTemplate.class);

        return xStream;
    }
}

qual é o melhor maneira?

Lucas_Cavalcanti

se ao invés de @Component vc usar @Deserializes(“application/json”) o VRaptor vai usar a classe…
mas tem que testar se isso vai deserializar do jeito que vc quer.

gabriel.mancini

ROLLBACK hehe

Lucas acho q vou por aki:

import java.io.InputStream;

import br.com.caelum.vraptor.deserialization.Deserializer;
import br.com.caelum.vraptor.deserialization.Deserializes;
import br.com.caelum.vraptor.resource.ResourceMethod;

@Deserializes({"application/json", "json", "text/javascript"})  
public class CustomJSONDeserialization implements Deserializer {

	@Override
	public Object[] deserialize(InputStream inputStream, ResourceMethod method) {
		// COMO EU FAÇO A DESERIALIZAÇÃO AQUI???
		return null;
	}
}

como eu faço ali?

Lucas_Cavalcanti

bom, o jeito mais fácil é usar form parameters :wink:

mas pra json, vc pode usar qqer biblioteca que parseia json. O XStream até faz isso, mas o deserializer é meio estranho… vc pode dar uma olhada no GSon tb…

Criado 10 de maio de 2011
Ultima resposta 19 de mai. de 2011
Respostas 26
Participantes 4