Spring MVC problema com data

Boa tarde pessoal. Eu novamente rs … seguinte criei uma página jsp onde o usuário digita alguns dados entre eles uma data. Quase todos os dados chegam no método que criei no spring sem problemas, com exceção de um. A data! :frowning: Cara estou a dois dias tentando resolver isso e nada! A data chega com valor nulo no método. O que será que está acontecendo?

PS:. Por favor ignorem a bagunça no bean tarefa. É que estou mechendo nele ha um tempo tentando arrumar esse problema.

JSP:

<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
	<head>
		<title>Tarefa a Ser Alterada</title>
	</head>
	
	<body>
		Informações da tarefa à ser alterada:<br />
		<form action="alteraTarefa" method="post">
			<input type="text" name="id" value="${tarefa.id}" readonly="true"><br />
			Descrição:<br />
			<textarea rows="5" cols="100" name="descricao">${tarefa.descricao}</textarea><br />
			Finalizado? <input type="checkbox" name="finalizado" value="true" ${tarefa.finalizado?'checked':''}/><br />
			Data de Finalização:<br />			
			<input type="text" name="dataFinalizacao">
			<br />
			<input type="submit" value="Alterar">		
		</form>
	</body>	
</html>

Metodo no Spring:

@RequestMapping("alteraTarefa")
	public String altera(Tarefa tarefa){
						
	TarefaDao dao = new TarefaDao();
	System.out.println("data em tarefascontroller alteratarefa == " + tarefa.getDataFinalizacao());
	dao.altera(tarefa);
	return "redirect:listaTarefas";
	
}

Tarefa Java Bean:

package br.com.caelum.tarefas.model;

import java.util.Date;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.GregorianCalendar;

import javax.validation.constraints.Size;

import org.springframework.format.annotation.DateTimeFormat;

import com.sun.istack.internal.NotNull;

public class Tarefa {
	
	private long id;
	@NotNull @Size(min=5, max=100)
	private String descricao;
	private boolean finalizado = false;
	@DateTimeFormat(pattern="yyyy-MM-dd")
	private Calendar dataFinalizacao;
	
	public void setId(long id){
		this.id = id;
	}
	public long getId(){
		return this.id;
	}
	
	public void setDescricao(String descricao){
		this.descricao = descricao;		
	}
	public String getDescricao(){
		return this.descricao;
	}
	
	public void setFinalizado(boolean finalizado){
		this.finalizado = finalizado;
	}
	public boolean getFinalizado(){
		return this.finalizado;
	}
	
	public void setDataFinalizacao(String dataFinalizacao){			
		
		/*
		DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");
		String dataStr = "24/02/2012";				
		Date date = sdf.parse(dataStr);
		Calendar cal = new GregorianCalendar();
		cal.setTimeInMillis(date.getTime()); 
		 */
		
		try{
			DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			Date data = df.parse(dataFinalizacao);
			Calendar calendario = new GregorianCalendar();				
			calendario.setTimeInMillis(data.getTime());
			System.out.println("\n\nItens abaixo em tarefa setDataFinalizacao\n");
			System.out.println("Data em setDataFinalizacao " + calendario.get(Calendar.DAY_OF_MONTH) + "/" + calendario.get(Calendar.MONTH) + "/" + calendario.get(Calendar.YEAR));
			this.dataFinalizacao = calendario;
			System.out.println("\nthis.dataFinalizacao == " + this.dataFinalizacao.get(Calendar.DAY_OF_MONTH) + "/" + this.dataFinalizacao.get(Calendar.MONTH) + "/" + this.dataFinalizacao.get(Calendar.YEAR));
		}catch(NullPointerException ex){
			//System.out.println("\n\n" + ex.getMessage() + " exceção null pointer em tarefa setDataFinalizacao\n");
			System.out.println("\n\nExceção null pointer em tarefa setDataFinalizacao\n");
			ex.printStackTrace();
		}catch(ParseException ex){
			System.out.println("\n\n" + ex.getMessage() + " exceção parse em tarefa setDataFinalizacao");
			
		}
	}	
	public Calendar getDataFinalizacao(){
		return this.dataFinalizacao;
	}
	
}

O problema é o seguinte, quando você envia uma data da JSP para o controller, essa data chega como uma String, porém você está esperando um Calendar, por isso o problema.
O Spring possui uma implementação que você pode adicionar ao seu controller, que dai ele faz a conversão:

    private SimpleDateFormat dateFormat;

    @Autowired
    public SeuController(SimpleDateFormat dateFormat) {
        this.dateFormat = dateFormat;
    }

    @InitBinder
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

Porém você só vai conseguir converter para java.util.Date. Como seu atributo é um Calendar, vai dar erro. Dai para resolver, ou você troca de Calendar para Date ou implementa sua propria classe de conversão nos padrões da classe CustomDateEditor. Pode usa-la como modelo para construir a sua.

[quote=romarcio]O problema é o seguinte, quando você envia uma data da JSP para o controller, essa data chega como uma String, porém você está esperando um Calendar, por isso o problema.
O Spring possui uma implementação que você pode adicionar ao seu controller, que dai ele faz a conversão:

    private SimpleDateFormat dateFormat;

    @Autowired
    public SeuController(SimpleDateFormat dateFormat) {
        this.dateFormat = dateFormat;
    }

    @InitBinder
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
    }

Porém você só vai conseguir converter para java.util.Date. Como seu atributo é um Calendar, vai dar erro. Dai para resolver, ou você troca de Calendar para Date ou implementa sua propria classe de conversão nos padrões da classe CustomDateEditor. Pode usa-la como modelo para construir a sua.
[/quote]

Oi Romarcio. Então cara depois de vários ajustes tentando resolver esse problema, eu coloquei o método setDataFinalização para receber uma String e lá dentro eu converto para Calendar. Recebendo uma String deveria funcionar não?

Sim, você pode criar um atributo do tipo String na Entidade para receber a data que vem da JSP e depois converter para outro tipo.
Só não esqueça de alterar na JSP para esse novo atributo.

Qual a exceção que está dando, é a mesma de antes?

É sim continua dando NullPointerException

Cola a exceção para eu ver.

Na exceção aparece apenas null … como se o valor do calendario não estive sendo mandado pela jsp. Caso adiante segue o stackTrace:

java.lang.NullPointerException
	at br.com.caelum.tarefas.dao.TarefaDao.altera(TarefaDao.java:130)
	at br.com.caelum.tarefas.controller.TarefasController.altera(TarefasController.java:95)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:616)
	at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:213)
	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:126)
	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:96)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:617)
	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:578)
	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:80)
	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:923)
	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:852)
	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:882)
	at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:789)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:169)
	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:987)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:579)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:309)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
	at java.lang.Thread.run(Thread.java:636)

Faz essa mudança: @RequestMapping("alteraTarefa") public String altera(@ModelAttribute("tarefa") Tarefa tarefa){ TarefaDao dao = new TarefaDao(); System.out.println("data em tarefascontroller alteratarefa == " + tarefa.getDataFinalizacao()); dao.altera(tarefa); return "redirect:listaTarefas"; }

Só uma coisa, sua JSP não está nos padrões do Spring MVC. Você está usando Struts 2.

Ta legal farei essa mudança e posto aqui no que deu. Mas me diz uma coisa. Como assim a jsp está no padrão struts2? Tipo … o que deveria fazer nessa jsp para ela ficar no padrão do spring mvc?

Você deve construir a JSP com as tags fornecidas pelo Spring MVC. Se não fizer assim, ele não vai buscar seus dados.

Procure na internet por Tutoriais Spring 3 MVC que vai achar bastante material.

Um exemplo do JSP com Spring:

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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Add Event</title>

</head>

<body>
<h1>Add User</h1>
<c:url var="viewUsersUrl" value="/users.html" />
<a href="${viewUsersUrl}">View All Users</a>

<br /><br />
<c:url var="addUserUrl" value="/users/save.html" />
<form:form modelAttribute="user" method="POST" action="${addUserUrl}">
	<form:label path="username">Username:</form:label>
	<form:input path="username"/><br />
	<form:label path="password">Password:</form:label>
	<form:input path="password"/><br />
	<input type="submit" value="Save User" />
</form:form>

</body>
</html>

Veja como muda as tags em relação as que você usa.
Fora que tem outras configurações que não sei se você fez.
A fonte do exemplo que passei: http://pbrajkumar.wordpress.com/2010/03/24/spring-3-0-mvc-hibernate-simplified-with-annotations-tutorial/