7
respostas

Spring MVC I - Aula 8 - mvcConversionService com Java8

Boa noite.

Na aula 8 do curso Spring MVC I ensina a criar um método único (mvcConversionService) para formatar as datas na aplicação.

Na aula, o professor utiliza a classe "Calendar" para o atributo da classe "Produto". Quando eu mudo o tipo do atributo para "LocalDate" do Java8, ocorre o erro abaixo:

"Failed to convert property value of type java.lang.String to required type java.time.LocalDate for property dataLancamento; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [@org.springframework.format.annotation.DateTimeFormat java.time.LocalDate] for value 05/05/2018; nested exception is java.lang.IllegalArgumentException: Parse attempt failed for value [05/05/2018]".

Procurei aqui no fórum e só achei 1 tópico que não me ajudou.

Peço ajuda de vocês para que eu consiga utilizar essa funcionalidade com a nova biblioteca do Java Time do Java8.

Obs.: tentei até utilizar a outra classe para formatação de data "DateTimeFormatterRegistrar", mas não funcionou também. É como se o Spring não utilizasse essa configuração.

Desde já agradeço a atenção!

Segue abaixo minha classe modelo:

package br.com.casadocodigo.loja.models;

import java.time.LocalDate;
import java.util.List;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.springframework.format.annotation.DateTimeFormat;

@Entity
public class Produto {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String titulo;
    private String descricao;
    private int paginas;

    @DateTimeFormat
    private LocalDate dataLancamento;

    public LocalDate getDataLancamento() {
        return dataLancamento;
    }
    public void setDataLancamento(LocalDate dataLancamento) {
        this.dataLancamento = dataLancamento;
    }

    @ElementCollection
    private List<Preco> precos;

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public List<Preco> getPrecos() {
        return precos;
    }
    public void setPrecos(List<Preco> precos) {
        this.precos = precos;
    }
    public String getTitulo() {
        return titulo;
    }
    public void setTitulo(String titulo) {
        this.titulo = titulo;
    }
    public String getDescricao() {
        return descricao;
    }
    public void setDescricao(String descricao) {
        this.descricao = descricao;
    }
    public int getPaginas() {
        return paginas;
    }
    public void setPaginas(int paginas) {
        this.paginas = paginas;
    }
    @Override
    public String toString() {
        return "Produto [id=" + id + ", titulo=" + titulo + ", descricao=" + descricao + ", paginas=" + paginas
                + ", dataLancamento=" + dataLancamento + ", precos=" + precos + "]";
    }
}

Segue a classe que tem o método implementado:

package br.com.casadocodigo.loja.conf;

import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.format.datetime.DateFormatterRegistrar;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;



import br.com.casadocodigo.loja.controllers.HomeController;
import br.com.casadocodigo.loja.daos.ProdutoDAO;

@EnableWebMvc
@ComponentScan(basePackageClasses= {HomeController.class, ProdutoDAO.class})
public class AppWebConfiguration {

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");

        return resolver;
    }

    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("/WEB-INF/messages");
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setCacheSeconds(1);

        return messageSource;
    }

    @Bean
    public FormattingConversionService mvcConversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        DateFormatterRegistrar formatterRegistrar = new DateFormatterRegistrar();
        formatterRegistrar.setFormatter(new DateFormatter("dd/MM/yyyy"));
        formatterRegistrar.registerFormatters(conversionService);

        return conversionService;
    }
}
7 respostas

Opa, eu preciso testar aqui com uma versão mais nova do spring. Dei uma olhada no código e parece que deveria funcionar, mas pode ser que tenha a ver com a versão mais nova. Vou precisar fazer um teste e te retornar.

Obrigado Alberto. Vou aguardar!

Caso tenha mudado, seria legal adicionar essa atualização no curso.

Oi Rodrigo, descobri algumas coisas, mas outras não. Como a gente espera apenas uma data, tenta usar LocalDate em vez de LocalDateTime.

A parte ruim. Não achei como fazer a configuração default para LocalDateTime... Tentei de tudo e não consegui fazer minha configuração funcionar. Se você colocar o pattern direto na annotation, funciona.

Se outra pessoa souber, por favor deixe aqui.

Olá Alberto, obrigado pelo retorno.

Então, eu utilizei a classe "LocalDate" mas também não deu certo. Só após não ter dado certo na primeira tentativa foi que eu tentei com "LocalDateTime".

De acordo com o propósito do exercício, você poderia por favor me mostrar como funciona com "LocalDate"?

Muito obrigado!

Só fiz adicionar um atributo do tipo LocalDate e colocar a annotation.

    @DateTimeFormat(pattern="yyyy-MM-dd")
    private LocalDate releaseDate;

Alberto boa noite.

E para gravar no banco de dados o padrão "dd/MM/yyyy". No caso, anotei meu atributo da classe nesse formato e continua gravando "yyyy/MM/dd".

O problema está na minha aplicação, porque eu mando imprimir no console o getDataLancamento após o binding do spring e ele já imprime errado.

Agradeço se puder me ajudar!

Opa, no banco você tem controle :). O driver jdbc já trata isso para você e coloca a data correta no localdate... Aí você formata como achar melhor :).