Vraptor, como formatar datas em um json?

36 respostas
psico.indie

Olá caros amigos, gostaria de formatar as datas retornadas pelo vRaptor. Ele está retornando datas como se fossem objetos. Alguém sabe como posso formatar datas?

{"success": true, "data": [ { "id": 150, "nome": "Maria das Dores", "dataNascimento": { "@class": "sql-timestamp", "$": "2011-04-16 00:00:00.0" }, "cpfCnpj": 123123, "rg": 0, "dataExpedicao": { "@class": "sql-timestamp", "$": "2011-01-31 00:00:00.0" }, "orgaoExpedidor": "", "limiteCredito": 0.0, "logradouro": "", "numero": 0, "bairro": "", "cidade": { "id": 126, "nome": "Cutias", "estado": { "id": 3, "sigla": "AP", "nome": "Amapá" } } ...} }

36 Respostas

Lucas_Cavalcanti

você pode sobrescrever o jsonSerialization, como nesse gist:

psico.indie

É só criar essa classe no meu projeto e pronto? Não preciso fazer nenhuma indicação em uma annotation?

Lucas_Cavalcanti

@Component nela é o suficiente

psico.indie

Não deu certo. :frowning:

Olha meu a função que retorna o json:

public void lista(){ List<Cliente> clientes = clienteDao.findAll(); result.use(ExtJSJson.class).from(clientes).success(true).serialize(); }

Detalhe, esse clienteDao está sendo injeto pelo Spring e o Controler é gerenciado pelo vraptor. Tem algum problema?

Lucas_Cavalcanti

então ao invés de sobrescrever o XStreamJSONSerialization, sobrescreva ExtJSJsonImpl…

o que eu te passei funcionaria se vc usasse result.use(json())

psico.indie

Tu já viu como está a classe ExtJSJsonImpl?

Não cosigo setar o atributo xstream pq ele não está encapsulado. Não tem como reutilizar essa componente.

psico.indie

Se tivesse bastava fazer:

@Component
public class CustomJSONSerialization extends ExtJSJsonImpl {
     
       
      public CustomJSONSerialization(HttpServletResponse response) {
		super(response);
		getXtream().registerConverter(new DateConverter("dd/MM/yyyy", new String[0]));
      }


}
Lucas_Cavalcanti

opa, sry…

o ExtJSJSon foi uma contribuição externa, então não seguiu muito o jeito normal do VRaptor de programar…

o que vc pode fazer é copiar essa classe para o seu projeto:

https://github.com/caelum/vraptor/blob/master/vraptor-core/src/main/java/br/com/caelum/vraptor/util/extjs/ExtJSJsonImpl.java

e mudar o xstream do construtor adicionando o seu converter…

o ideal era que essa classe usasse o JSONSerialization

já tem uma issue pra fazer isso: https://github.com/caelum/vraptor/issues/292

na próxima versão isso vai estar mais configurável

psico.indie

É, o negócio lá tá parecendo uma briga de faca aqui do interior daqui do Ceará.

psico.indie

Lucas, não funcionou. Após as implementações abaixo, continua não formatando a data. É algo que eu estou fazendo errado?

mesmo fazendo isso:

public void lista(){ List<Cliente> clientes = clienteDao.findAll(); result.use(json()).from(clientes, "data").serialize(); }

@Component
public class CustomJSONSerialization extends XStreamJSONSerialization {
      
    public CustomJSONSerialization(HttpServletResponse response,TypeNameExtractor extractor, ProxyInitializer initializer) {
        super(response, extractor, initializer);
    }
       
    @Override
    public XStream getXStream() {
        XStream xstream = super.getXStream();
        xstream.registerConverter(new DateConverter("dd/MM/yyyy", new String[0]));
        return xstream;
    }
  
}
Lucas_Cavalcanti

a sua data é um Date ou um Calendar? é Date do java.util ou java.sql?

psico.indie

java.util.Date

psico.indie

Taqui a criança:

package br.com.drover.entity;


import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.SequenceGenerator;

import org.springframework.beans.factory.annotation.Autowired;

@Entity
@SequenceGenerator(name="CLIENTE_S",initialValue=1,sequenceName="CLIENTE_S")
public class Cliente {
	
	@Id
	@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="CLIENTE_S")
	private Integer id;
	
	private String nome;
	
	private Boolean isPessoaJuridica;

	private Date dataNascimento;
	
	private Long cpfCnpj;
	
	private Long rg;

	private Date dataExpedicao ;

	private String orgaoExpedidor;
	
	private Double limiteCredito;
	
	private String logradouro;
	
	private Integer numero;
	
	private String bairro;
	
	private String CEP;
	
	private String nomePai;
	
	private String nomeMae;
	
	@ManyToOne
	private Cidade cidade;
	
	public Cliente() {
		
	}
	
	public Cliente(Integer  id) {
		this.id = id;
	}
	
	public String getNome() {
		return nome;
	}

	public void setName(String nome) {
		this.nome = nome;
	}
	
	
	public Integer getId() {
		return id;
	}

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

	public Long getCpfCnpj() {
		return cpfCnpj;
	}

	public void setCpfCnpj(Long cpfCnpj) {
		this.cpfCnpj = cpfCnpj;
	}

	public String getLogradouro() {
		return logradouro;
	}

	public void setLogradouro(String logradouro) {
		this.logradouro = logradouro;
	}

	public String getBairro() {
		return bairro;
	}

	public void setBairro(String bairro) {
		this.bairro = bairro;
	}

	public Cidade getCidade() {
		return cidade;
	}

	@Autowired
	public void setCidade(Cidade cidade) {
		this.cidade = cidade;
	}

	public Double getLimiteCredito() {
		return limiteCredito;
	}

	public void setLimiteCredito(Double limiteCredito) {
		this.limiteCredito = limiteCredito;
	}

	public String getNomePai() {
		return nomePai;
	}

	public void setNomePai(String nomePai) {
		this.nomePai = nomePai;
	}

	public String getNomeMae() {
		return nomeMae;
	}

	public void setNomeMae(String nomeMae) {
		this.nomeMae = nomeMae;
	}

	public Long getRg() {
		return rg;
	}

	public void setRg(Long rg) {
		this.rg = rg;
	}

	public String getOrgaoExpedidor() {
		return orgaoExpedidor;
	}

	public void setOrgaoExpedidor(String orgacaoExpedidor) {
		this.orgaoExpedidor = orgacaoExpedidor;
	}

	public Boolean getIsPessoaJuridica() {
		return isPessoaJuridica;
	}

	public void setIsPessoaJuridica(Boolean isPessoaJuridica) {
		this.isPessoaJuridica = isPessoaJuridica;
	}

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

	public void setCEP(String cEP) {
		CEP = cEP;
	}

	public String getCEP() {
		return CEP;
	}

	public void setNumero(Integer numero) {
		this.numero = numero;
	}

	public Integer getNumero() {
		return numero;
	}
	
	public Date getDataExpedicao() {
		return dataExpedicao;
	}

	public void setDataExpedicao(Date dataExpedicao) {
		this.dataExpedicao = dataExpedicao;
	}

	public Date getDataNascimento() {
		return dataNascimento;
	}

	public void setDataNascimento(Date dataNascimento) {
		this.dataNascimento = dataNascimento;
	}
	
}
Lucas_Cavalcanti

troca o:

xstream.registerConverter(new DateConverter("dd/MM/yyyy", new String[0]));

por

xstream.registerConverter(new SingleValueConverter() {

   public String toString(Object value) {
         return new SimpleDateFormat("dd/MM/yyyy").format(value);
   }

   public boolean canConvert(Class clazz) {
        return Date.class.isAssignableFrom(clazz);
   }

   public Object fromString(String value) {
        return null; //não é usado
   }
});
psico.indie

Lucas, percebi que o Hibernate está retornando um Timestamp no lugar de um Date. Acho que deve ser por isso que ainda não funcionou. Segue screemshot.


Lucas_Cavalcanti

mas se o seu campo está declarado como date não deveria ter problema…

vc colocou o converter implementado como eu te falei? importou de java.util.Date?

psico.indie

Aindan não deu. Ele converte, mas converte dentro de uma estrutura própria. Como se fosse um objeto:

“dataNascimento”: {"@class": “sql-date”,"$": “2011-03-30”},“cpfCnpj”: [telefone removido],“rg”: 2002001345512,“dataExpedicao”: {"@class": “sql-date”,"$": “2011-06-27”}

Lucas_Cavalcanti

só pra confirmar, seu custom está assim?

import java.util.Date;
import br.com.caelum.vraptor.ioc.Component;

@Component  
public class CustomJSONSerialization extends XStreamJSONSerialization {  
        
    public CustomJSONSerialization(HttpServletResponse response,TypeNameExtractor extractor, ProxyInitializer initializer) {  
        super(response, extractor, initializer);  
    }  
         
    @Override  
    public XStream getXStream() {  
        XStream xstream = super.getXStream();  
        xstream.registerConverter(new   SingleValueConverter() {  
  
           public String toString(Object value) {  
                 return new  SimpleDateFormat("dd/MM/yyyy").format(value);  
           }  
  
           public boolean canConvert(Class clazz) {  
                return Date.class.isAssignableFrom(clazz);  
           }  
  
           public Object fromString(String value) {  
              return null; //não é usado  
           }  
        });   
        return xstream;  
    }  
    
}

inclusive os imports?
o que me parece é que não está passando por essa classe…

psico.indie

Meu custon está assim e está sendo executado. Já executei e confirmei isso. Amanhã eu vou fazer um upload do projeto para o github pra você ver como está tudo certinho.

Lucas_Cavalcanti

mas o converter está sendo executado?
coloque um breakpoint no método toString(Object)

psico.indie

É estranho, eu sei. Mas está sendo executado sim. Já verifiquei.
Coloquei a versão do projeto aqui: https://github.com/rafaelreuber/drover-vraptor
Se você puder me ajudar, ficarei muito agradecido.

Lucas_Cavalcanti

vc ainda está usando new DateConverter… é pra usar o SingleValueConverter que eu passei acima

psico.indie

Eu coloquei como você disse. Tá daquele jeito pq eu esqueci de commitar.

Lucas_Cavalcanti

no toString(Object), coloque um throw new RuntimeException()… acho que não está passando por lá, senão estaria funcionando

psico.indie
GRAVE: Servlet.service() for servlet [default] in context with path [/drover] threw exception
br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: java.lang.RuntimeException
	at br.com.caelum.vraptor.interceptor.ExecuteMethodInterceptor.intercept(ExecuteMethodInterceptor.java:96)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.LazyInterceptorHandler.execute(LazyInterceptorHandler.java:61)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.InstantiateInterceptor.intercept(InstantiateInterceptor.java:48)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.ExceptionHandlerInterceptor.intercept(ExceptionHandlerInterceptor.java:71)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:56)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.FlashInterceptor.intercept(FlashInterceptor.java:83)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.interceptor.ResourceLookupInterceptor.intercept(ResourceLookupInterceptor.java:69)
	at br.com.caelum.vraptor.core.ToInstantiateInterceptorHandler.execute(ToInstantiateInterceptorHandler.java:54)
	at br.com.caelum.vraptor.core.DefaultInterceptorStack.next(DefaultInterceptorStack.java:54)
	at br.com.caelum.vraptor.core.EnhancedRequestExecution.execute(EnhancedRequestExecution.java:23)
	at br.com.caelum.vraptor.VRaptor$1.insideRequest(VRaptor.java:92)
	at br.com.caelum.vraptor.ioc.spring.SpringProvider.provideForRequest(SpringProvider.java:58)
	at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:89)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:242)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:240)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:203)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:108)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:558)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:379)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:242)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:259)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:281)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.RuntimeException
	at br.com.drover.util.CustomJSONSerialization$1.toString(CustomJSONSerialization.java:33)
	at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.toString(SingleValueConverterWrapper.java:37)
	at com.thoughtworks.xstream.converters.SingleValueConverterWrapper.marshal(SingleValueConverterWrapper.java:45)
	at com.thoughtworks.xstream.core.TreeMarshaller.convert(TreeMarshaller.java:86)
	at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:78)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.marshallField(AbstractReflectionConverter.java:157)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$2.writeField(AbstractReflectionConverter.java:148)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter$2.visit(AbstractReflectionConverter.java:118)
	at com.thoughtworks.xstream.converters.reflection.PureJavaReflectionProvider.visitSerializableFields(PureJavaReflectionProvider.java:129)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doMarshal(AbstractReflectionConverter.java:100)
	at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.marshal(AbstractReflectionConverter.java:58)
	at com.thoughtworks.xstream.core.TreeMarshaller.convert(TreeMarshaller.java:86)
	at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:78)
	at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:63)
	at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.writeItem(AbstractCollectionConverter.java:64)
	at com.thoughtworks.xstream.converters.collections.CollectionConverter.marshal(CollectionConverter.java:55)
	at com.thoughtworks.xstream.core.TreeMarshaller.convert(TreeMarshaller.java:86)
	at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:78)
	at com.thoughtworks.xstream.core.TreeMarshaller.convertAnother(TreeMarshaller.java:63)
	at com.thoughtworks.xstream.core.TreeMarshaller.start(TreeMarshaller.java:98)
	at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.marshal(AbstractTreeMarshallingStrategy.java:38)
	at com.thoughtworks.xstream.XStream.marshal(XStream.java:837)
	at com.thoughtworks.xstream.XStream.marshal(XStream.java:826)
	at com.thoughtworks.xstream.XStream.toXML(XStream.java:801)
	at br.com.caelum.vraptor.serialization.xstream.XStreamSerializer.serialize(XStreamSerializer.java:237)
	at br.com.drover.controller.ClientesController.lista(ClientesController.java:30)
	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)
	... 39 more
psico.indie

Ele está passando por lá sim. Também acho que deveria estar funcionando. Não estou entendendo o porquê de não estar funcionando.

Lucas_Cavalcanti

commita a última versão no seu projeto, que eu dou uma olhada

psico.indie

Commitei:

Lucas_Cavalcanti

adiciona isso no CustomJson:

xstream.aliasSystemAttribute(null, "class");

o xstream coloca o @class sempre que vc usa uma classe diferente da declarada no objeto…

psico.indie

Sendo assim, não bastava anotar as datas com @Temporal(TemporalType.DATE)?

Lucas_Cavalcanti

não… pq o jdbc retorna java.sql.Date, não java.util.Date

psico.indie

Deu certo! Esse XStream parece meio complicadinho.

Lucas_Cavalcanti

é nada :wink:
vai fazer essa mesma coisa em JAX-B ou coisa do tipo rsrs

psico.indie

Lucas, só uma pergunta: seria muito complicado implentar o vRaptor para deserealizar json para objectos java?

Lucas_Cavalcanti

não… só criar um deserializer baseado nesse daqui:

só que mudando o getXStream pra ficar parecido com o do :

mudando o accept pra “application/json”

lucasmurata

Nossa, esse tópico salvou as minhas madrugadas com esse codigo:

xstream.aliasSystemAttribute(null, "class");

Valeu.

Criado 4 de julho de 2011
Ultima resposta 5 de out. de 2011
Respostas 36
Participantes 3