Erro - java.lang.NumberFormatException: For input string: "" - Exercício 9.7 (Apostila Caelum - FJ-21) [RESOLVIDO]

Olá,

Estou aprendendo Java Web e fazendo um projeto de Agenda, acompanhando a apostila do curso FJ-21 da Caelum. Peço a ajuda de vocês para conseguir resolver este problema.

No exercício 9.7 de MVC eu segui os passos exatamente como estão descritos na apostila e quando eu acesso “lista-contatos.jsp” e clico “Remover” em algum contato aparece o erro abaixo:

threw exception [A lógica de negócios causou uma exceção!] with root cause
java.lang.NumberFormatException: For input string: “”

Segue abaixo os códigos das classes envolvidas:

package br.com.renato.bean;

import java.util.Calendar;

public class Contato {

private Long id;
private String nome;
private String email;
private String endereco;
private Calendar dataNascimento;

Getters e Setters...

//Getter/Setter - id
public Long getId() {
	return id;
}

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

//Getter/Setter - nome
public String getNome() {
	return nome;
}

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

//Getter/Setter - email
public String getEmail() {
	return email;
}

public void setEmail(String email) {
	this.email = email;
}

//Getter/Setter - endereco
public String getEndereco() {
	return endereco;
}

public void setEndereco(String endereco) {
	this.endereco = endereco;
}

//Getter/Setter - dataNascimento
public Calendar getDataNascimento() {
	return dataNascimento;
}

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

}

package br.com.renato.dao;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import br.com.renato.bean.Contato;
import br.com.renato.connection.ConnectionFactory;

public class ContatoDao {

private Connection connection;

public ContatoDao(){
	this.connection = new ConnectionFactory().getConnection();
}

public void adiciona (Contato contato){
	
	String sql = "insert into contatos" + "(nome, email, endereco, dataNascimento)" + "values (?, ?, ?, ?)";
	
	
	try{
		
		PreparedStatement stmt = connection.prepareStatement(sql);
		
		stmt.setString(1, contato.getNome());
		stmt.setString(2, contato.getEmail());
		stmt.setString(3, contato.getEndereco());
		stmt.setDate(4, new Date(contato.getDataNascimento().getTimeInMillis()));
		
		stmt.execute();
		stmt.close();
		
	} catch (SQLException e){
		throw new RuntimeException (e);
	}
	
}

public List<Contato> getLista(){
	try{
		
		PreparedStatement stmt = this.connection.prepareStatement("select * from contatos");
		List<Contato> contatos = new ArrayList<Contato>();
		ResultSet rs = stmt.executeQuery();
		
		while (rs.next()){
			
			Contato contato = new Contato();
			contato.setId(rs.getLong("id"));
			contato.setNome(rs.getString("nome"));
			contato.setEmail(rs.getString("email"));
			contato.setEndereco(rs.getString("endereco"));
			
			Calendar data = Calendar.getInstance();
			data.setTime(rs.getDate("dataNascimento"));
			contato.setDataNascimento(data);
			
			contatos.add(contato);
		}
		
		rs.close();
		stmt.close();
		return contatos;
		
	} catch (SQLException e){
		throw new RuntimeException (e);
	}
}

public void altera (Contato contato){
	String sql = "update contatos set nome=?, email=?, endereco=?, dataNascimento=? where id=?";
	
	try{
		
		PreparedStatement stmt = connection.prepareStatement(sql);
		
		stmt.setString(1, contato.getNome());
		stmt.setString(2, contato.getEmail());
		stmt.setString(3, contato.getEndereco());
		stmt.setDate(4, new Date(contato.getDataNascimento().getTimeInMillis()));
		stmt.setLong(5, contato.getId());
		
		stmt.execute();
		stmt.close();
		
	} catch (SQLException e){
		throw new RuntimeException (e);
	}
}

public void remove (Contato contato){
	try{
		
		PreparedStatement stmt = connection.prepareStatement("delete * from contatos where id=?");
		
		stmt.setLong(1,  contato.getId());
		
		stmt.execute();
		stmt.close();
		
	} catch (SQLException e){
		throw new RuntimeException (e);
	}
}

}

package br.com.renato.mvc.logica;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public interface Logica {

String executa (HttpServletRequest request, HttpServletResponse response) throws Exception; 

}

package br.com.renato.mvc.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import br.com.renato.mvc.logica.Logica;

@WebServlet ("/mvc")
public class ControllerServlet extends HttpServlet{

@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
	
	String parametro = request.getParameter("logica");
	String nomeDaClasse = "br.com.renato.mvc.logica." + parametro;
	
	try{
		
		Class classe = Class.forName(nomeDaClasse);
		
		Logica logica = (Logica) classe.newInstance();
		String pagina = logica.executa(request, response);
		
		request.getRequestDispatcher(pagina).forward(request, response);
		
	} catch (Exception e){
		throw new ServletException ("A lógica de negócios causou uma exceção!", e);
	}	
}

}

package br.com.renato.mvc.logica;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import br.com.renato.bean.Contato;
import br.com.renato.dao.ContatoDao;

public class RemoveContatoLogic implements Logica {

@Override
public String executa(HttpServletRequest request, HttpServletResponse response) throws Exception {
	
	long id = Long.parseLong(request.getParameter("id"));
	
	Contato contato = new Contato();
	contato.setId(id);
	
	ContatoDao dao = new ContatoDao();
	dao.remove(contato);
	
	System.out.println("Excluindo contato...");
	
	return "lista-contatos.jsp";
	
}

}

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

<%@ taglib uri=“http://java.sun.com/jsp/jstl/fmt” prefix=“fmt” %>

<c:import url=“cabecalho.jsp”/>

<jsp:useBean id=“dao” class=“br.com.renato.dao.ContatoDao”/>

<table>

	<c:forEach var="contato" items="${dao.lista}">
	
		<tr>
		
			<td>${contato.nome}</td>
			<td>
				<c:choose>
				
					<c:when test="${not empty contato.email}">
						<a href="mailto:${contato.email}">${contato.email}</a>
					</c:when>
				
					<c:otherwise>
						E-mail não informado
					</c:otherwise>					
				
				</c:choose>
				
			</td>	
			<td>${contato.endereco}</td>
			<td><fmt:formatDate value="${contato.dataNascimento.time}" pattern="dd/MM/yyyy"/></td>
			<td>
				<a href="mvc?logica=RemoveContatoLogic&id=${contado.id}">Remover</a>
			</td>
			
		</tr>
		
	</c:forEach>
	
</table>

<c:import url=“rodape.jsp”/>

NumberFormatException acontece geralmente quando você tenta converter uma String para um número (int, long, double, etc), e o conteúdo da String está vazio ou não é um número esperado.

Qual é a linha que tá dando o erro? Aparece no stack trace, mas você não colou aqui.

Desculpe, mas é erro de códigos que você fala?
Se for erro de códigos, não tem.

Segue o log de erros. Espero ter ajudado.

fev 27, 2017 12:17:50 PM org.apache.catalina.core.StandardWrapperValve invoke

GRAVE: Servlet.service() for servlet [br.com.renato.mvc.servlet.ControllerServlet] in context with path [/agenda] threw exception [A lógica de negócios causou uma exceção!] with root cause
java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at br.com.renato.mvc.logica.RemoveContatoLogic.executa(RemoveContatoLogic.java:14)
at br.com.renato.mvc.servlet.ControllerServlet.service(ControllerServlet.java:27)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:474)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
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:349)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:783)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:798)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1434)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)

Tipo, quando acontece um erro, se você olhar no log do erro (ou stack trace) aparece a linha de código onde o erro aconteceu.

O problema está na classe RemoveContatoLogic, no método executa, na linha:

long id = Long.parseLong(request.getParameter("id"));

A chamada request.getParameter("id") está retornando uma String vazia, que é responsável pela exceção NumberFormatException no método parseLong. Existe o parâmetro id na requisição?

Requisição vc fala no banco de dados?

Qdo um contato é adicionado, automaticamente gera o Id dele, que na ordem dos contatos o número varia. É isso?

pra add a tabela no banco eu eu usei o código abaixo:

create table contatos (
id BIGINT NOT NULL AUTO_INCREMENT,
nome VARCHAR (255),
email VARCHAR (255),
endereco VARCHAR (255),
dataNascimento DATE,
primary key (id)
);

Não, a requisição HTTP, aquele parâmetro do método executa do tipo HttpServletRequest. Você está tentando pegar um parâmetro chamado "id", sendo que ele aparentemente não existe dentro da requisição.

Entendi.
Mas nessa linha eu não estou adicionando o “id” como parametro?

long id = Long.parseLong(request.getParameter(“id”));

Tem alguma sugestão?

Não, você está dizendo:

  • Objeto da requisição, por favor me dê o parâmetro chamado de “id” que o cliente me enviou.

      request.getParameter("id");
    

E o objeto da requisição está respondendo:

  • Não tem nenhum objeto chamado “id” aqui, acho que o cliente não enviou nada. Toma aqui essa String vazia.

      ""
    

Você está pegando essa String vazia e dizendo para o método parseLong:

  • Método parseLong, pegue essa String vazia, interprete-a e me dê o número que ela tem:

      Long.parseLong("");
    

O método está te dizendo:

  • Não tem nada nessa String que você me passou. Toma aí uma NumberFormatException

Você precisa enviar para o servlet o parâmetro ID quando fizer a requisição HTTP. Se você não tem ideia do que eu estou falando, precisa dar uma estudada no protocolo HTTP e no básico de Servlet antes de tentar fazer o que tá tentando.

Amigo, consegui resolver aqui e não acredito que era um erro tão banal:

Remover

Repare que o certo seria “contato.id” e está “contado.id”.

De resto não fiz absolutamente nada no código, além de corrigir isto e funcionou perfeitamente.

Dei uma re-estudada depois das suas dicas e vou continuar estudando e revisar os pontos que você destacou também. Obrigado pela ajuda. Vou atualizar o tópico para RESOLVIDO.