Solucionado (ver solução)
Solucionado
(ver solução)
2
respostas

DÚVIDAS DE CONVERSÃO DO STRING PARA CALENDAR

Boa Noite, estou com o seguinte problema, muitíssimo chato, o Spring não está conseguindo CONVERTER o <form:input type="date" para o Calendar da minha "Entity", já tentei de diversas formas e nada, e por isso solicito mais uma vez a ajuda de vocês se possível, a exception:

org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 1 errors
Field error in object 'produtoPorFornecedor' on field 'dataVencimento': rejected value [2017-07-10]; codes [typeMismatch.produtoPorFornecedor.dataVencimento,typeMismatch.dataVencimento,typeMismatch.java.util.Calendar,typeMismatch]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [produtoPorFornecedor.dataVencimento,dataVencimento]; arguments []; default message [dataVencimento]]; default message [Failed to convert property value of type 'java.lang.String' to required type 'java.util.Calendar' for property 'dataVencimento'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type java.lang.String to type @org.springframework.format.annotation.DateTimeFormat java.util.Calendar for value '2017-07-10'; nested exception is java.lang.IllegalArgumentException: Unable to parse '2017-07-10']
    at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:112)
    at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:79)
    at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:157)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:124)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:781)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:721)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:83)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:961)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:863)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:837)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:88)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:118)
    at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:105)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342)
    at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192)
    at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160)
    at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344)
    at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:475)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:624)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:498)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:796)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1368)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

JSP: (Se eu enviar a data sem o "type=date" ai o spring consegue converter, mas com o DATE ele deixa de uma forma fácil para colocar a data, gostaria de saber se tem como resolver esse erro)

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%@ taglib tagdir="/WEB-INF/tags" prefix="tags" %>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>  
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>  


<tags:pageTemplate titulo="Dar Baixa">

    <form:form action="${s:mvcUrl('EAC#adicionaAvariados').build()}" method="POST" commandName="produtoPorFornecedor" > 

        <div class="container">

            <div class="form-group">
                <label>Empresa</label>
                    <select name="empresa.nome" >
                        <c:forEach items="${empresas}" var="empresaLista">
                            <option>
                                ${empresaLista.nome}
                            </option>
                        </c:forEach>
                    </select>
            </div>

            <!-- Busca todos os fornecedores e coloca em um ListBox -->    
            <div class="form-group">
                <label>Fornecedor</label>    
                <select name="fornecedor.nome">
                    <c:forEach items="${fornecedores}" var="fornecedor">
                        <option>${fornecedor.nome}</option>
                    </c:forEach>
                </select>
            </div>

            <div class="form-group">
                <label>Quantidade</label>
                <form:input path="quantidadeTotal" class="form-control"  />
            </div>
            <div class="form-group">
                <label>Código de Barra</label>
                <form:input path="produto.codBarra" class="form-control" />
            </div>
            <div class="form-group">
                <label>Descrição Produto</label>
                <form:input path="produto.nome" class="form-control" />
            </div>
            <div class="form-group">
                <label>Data Vencido</label>
                <form:input type="date" path="dataVencimento" class="form-control" />
            </div>

            <button type="submit" class="btn btn-primary">Cadastrar</button>        
        </div>

    </form:form>
    ${sucesso}

</tags:pageTemplate>

ENTIDADE --------------------------------

package br.com.model;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;

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

import org.springframework.format.annotation.DateTimeFormat;

@Entity
public class ProdutoPorFornecedor {

    /*
     *  Fornecedor terá um List dessa classe para indicar quantidadeTotal de produtos por FORNECEDOR
     */

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    private Produto produto;

    @ManyToOne(fetch=FetchType.EAGER)
    private Fornecedor fornecedor;

    private int quantidadeTotal;

    @DateTimeFormat
    private Calendar dataVencimento;

    @ManyToOne
    private Empresa empresa;


    // CONSTRUCTOR
    @Deprecated
    public ProdutoPorFornecedor() {
    }

    public ProdutoPorFornecedor(Long id) {
        this.id = id;
    }


    // GET / SET
    public Empresa getEmpresa() {
        return empresa;
    }

    public void setEmpresa(Empresa empresa) {
        this.empresa = empresa;
    }

    public Calendar getDataVencimento() {
        return dataVencimento;
    }

    public void setDataVencimento(Calendar dataVencimento) {

            this.dataVencimento = dataVencimento;
    }

    public Long getId() {
        return id;
    }

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

    public Produto getProduto() {
        return produto;
    }

    public void setProduto(Produto produto) {
        this.produto = produto;
    }

    public Fornecedor getFornecedor() {
        return fornecedor;
    }

    public String getFornecedorNome() {
        return fornecedor.getNome();
    }

    public void setFornecedor(Fornecedor fornecedor) {
        this.fornecedor = fornecedor;
    }

    public int getQuantidadeTotal() {
        return quantidadeTotal;
    }

    public void setQuantidadeTotal(int quantidadeTotal) {
        this.quantidadeTotal += quantidadeTotal;
    }

}

CONTROLLER---------------------------------

package br.com.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import br.com.dao.EmpresaDAO;
import br.com.dao.FornecedorDAO;
import br.com.dao.ProdutoDAO;
import br.com.dao.ProdutoPorFornecedorDAO;
import br.com.model.Empresa;
import br.com.model.Produto;
import br.com.model.ProdutoPorFornecedor;

@Controller
@RequestMapping("/entradaAvariados")
@Scope(value=WebApplicationContext.SCOPE_REQUEST)                                            // OLHAR INFO (BEAN/SCOPE) = Aqui diz que cada usuário que faça uma REQUISIÇÃO que utilize essa classe, irá instânciar essa classe para cada usuário. (Por padrão seria utilizado essa mesma classe com a mesma requisição para todos os usuários)
public class EntradaAvariadosController {

    @Autowired
    private EmpresaDAO empresaDao;

    @Autowired
    private ProdutoDAO produtoDao;

    @Autowired
    private FornecedorDAO fornecedorDao;

    @Autowired
    private ProdutoPorFornecedorDAO produtoPorFornecedorDao;


    // Tela de entrada dos AVARIADOS
    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView indexAvariados(ProdutoPorFornecedor produtoPorFornecedor){

        // Busca todos fornecedores
        ModelAndView mv = new ModelAndView("entradas/entrada_avariados");
        mv.addObject("fornecedores",fornecedorDao.findAll());
        mv.addObject("empresas",empresaDao.findAll());

        return mv;
    }



    // MÉTODOS
    @RequestMapping(value="add",method=RequestMethod.POST)
    @CacheEvict(value={"AllProdutos" , "produtoEspecifico", "AllEntradas", "entradaEspecifica", "entradaEspecifica2"}, allEntries=true)
    public ModelAndView adicionaAvariados(ProdutoPorFornecedor produtoPorFornecedor, HttpServletRequest req, RedirectAttributes attributes){

        gravaAlteracoes(produtoPorFornecedor, req);
//        produtoPorFornecedorDao.grava(produtoPorFornecedor);                                         // (Ainda está fazendo 1 busca para cada OBJECT dentro dele, e depois fazendo o insert (Por enquanto))

        ModelAndView mv = new ModelAndView("redirect:/entradaAvariados");
        attributes.addFlashAttribute("sucesso", "Fornecedor adicionado com sucesso");

        return mv;
    }


    private void gravaAlteracoes(ProdutoPorFornecedor produtoPorFornecedor, HttpServletRequest req) {
        String empresaNome = req.getParameter("empresa.nome");
        String fornecedorNome = req.getParameter("fornecedor.nome");
        String produtoCodBarra = req.getParameter("produto.codBarra");
        String produtoNome = req.getParameter("produto.nome");

        Empresa empresa = empresaDao.find(empresaNome);
        Produto produto = produtoDao.find(produtoCodBarra, produtoNome, empresaNome, fornecedorNome);
        System.out.println("PASSOU PRODUTO");
        produtoPorFornecedorDao.find(empresa, fornecedorNome, produtoPorFornecedor, produto, produtoPorFornecedor.getQuantidadeTotal());
    }




}

CONF - WEB

package br.com.conf;

import java.util.concurrent.TimeUnit;

import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.guava.GuavaCacheManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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.client.RestTemplate;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

import com.google.common.cache.CacheBuilder;

import br.com.controller.HomeController;
import br.com.dao.FornecedorDAO;
import br.com.model.Fornecedor;

@EnableWebMvc                                                                                // Indica que essa classe trata todos os trabalhos referente WEB do SPRING
@ComponentScan(basePackageClasses={HomeController.class, Fornecedor.class, FornecedorDAO.class})                    // Colocar uma classe de cada package que utilize annotation do SPRING, ex: (@Controller, @Repository, @File)
@EnableCaching
public class AppWebConfiguration extends WebMvcConfigurerAdapter {


    // Mostra ao SPRING o local das VIEWS
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver(){

        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");                                                // Local das Views
        resolver.setSuffix(".jsp");                                                            // Tirando a obrigatoriedade de digitar ".jsp" ao se referênciar a uma view

        return resolver;
    }


    // Para que o spring libere as requisições referentes ao CSS/FONTS/SCRIP (Método herdado de WebMvcConfigurerAdapter)
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }


    // FAZENDO QUE A FORMATAÇÃO(pattern) DO @DateTimeFormat SEJA POR DEFAULT ABAIXO:
        @Bean
        public FormattingConversionService mvcConversionService(){
            DefaultFormattingConversionService conversionService = 
                    new DefaultFormattingConversionService();                                    // Responsável pelo serviço de conversão de formato. 
            DateFormatterRegistrar registrar = new DateFormatterRegistrar();
            registrar.setFormatter(new DateFormatter("yyyy/MM/dd"));                            // Fará o registro do formato de data usado para a conversão. Este segundo objeto espera receber outro objeto do tipo DateFormatter que será quem efetivamente guarda o padrão da data
            registrar.registerFormatters(conversionService);                                    // Usar o registrador para registar o padrão de data no serviço de conversão.

            return conversionService;                                                            // Como agora ele está "Registrado" pode retorna-lo, pois agora ele tem o "pattern" padrão. 
        }


        // 1.2 CACHÊ MANAGER - PARA HABILITAR O "Cacheable" (Ensinando para o Spring, para que o spring consiga injetar o Cacheable)
        @Bean
        public CacheManager cacheManager(){
//         return new ConcurrentMapCacheManager();                                                // (Utilizado para testes) Criando um MAP(KEY,VALUE) para guardar nosso CACHE em um CACHE MANAGER
        CacheBuilder<Object, Object> builder = CacheBuilder.newBuilder()                    // 1.1 CRIA UM CACHE MANAGER
            .maximumSize(100).expireAfterAccess(5, TimeUnit.MINUTES);                            // 1.2 ESPECIFICA O TAMANHO MÁXIMO DE ELEMENTOS QUE CABE NESSE "CACHE MANAGER" e ESPECIFICANDO QUE IRÁ EXPIRAR ESSE CACHÊ EM 5 MINUTOS (Mas em produção pode botar para 1 dia)

           GuavaCacheManager manager = new GuavaCacheManager();
           manager.setCacheBuilder(builder);                                                    // 1.3 Guarda o CACHE MANAGER criado, dentro do GUAVA do google e retorna (É preciso colocar as DEPENDENCY do GUAVA).

           return manager;
        }


        // CRIADO PARA QUE O SPRING SAIBA INJETAR A DEPENDÊNCIA REFERENTE A ESSA CLASS (JPAProductionConfiguration)
        @Bean
        public RestTemplate restTemplate(){
            return new RestTemplate();
        }


}
2 respostas
solução!

Fala Frank, tudo bem ?

O converter de String pra Calendar do Spring trabalha no padrão americano de datas M/d/yy, por isso a falha pra converter a String que vem do campo tipo date que trabalha no padrão yyyy/MM/dd.

É simples resolver:

@DateTimeFormat(pattern="yyyy-MM-dd")
private Calendar dataVencimento;

Ou usar a própria ISO que baseia o formato de data usado pelo tipo date.

@DateTimeFormat(iso=ISO.DATE)
private Calendar dataVencimento;

Abraço!

Muito obrigado Rafael, pela explicação e pela ajuda.

Quer mergulhar em tecnologia e aprendizagem?

Receba a newsletter que o nosso CEO escreve pessoalmente, com insights do mercado de trabalho, ciência e desenvolvimento de software