JSF - Com 2 HTMLSelectOneMenu aninhados os valores no HTMLInputText não aparecem

Boa tarde!

Sou iniciante em JSF, e estou esbarrando em um problema que deve ser muito simples de resolver para alguem que conheça de JSF.

Tenho dois HTMLSelectOneMenu aninhados, no caso classico Estados > Cidades. Quando é selecionado no primeiro HTMLSelectOneMenu um estado, são carregadas as cidades para esse estado no segundo HTMLSelecOneMenu. Até aki, tudo bem (depois de apanhar um pouco, criei os converters do Estado e da Cidade e subescrevi o equals da classe Estado e da classe Cidade e agora está tudo rolando certinho!)

Porem, o meu objeto Cidade possui dois campos int que devem ser editados: valorComp e diasComp.

Criei na página dois HTMLInputText, um para cada campo. Criei um objeto Cidade no meu ManagedBean, e apontei os campos para a propriedade value dos HTMLInputText criados.

O problema é que esses dois valores não aparecem no HTMLInputText nem com Reza Brava! oO

Depois de testar por horas, eu coloquei um breakpoint no setValorComp e eu notei que ele é acionando “sózinho pelo JSF” setando “0”. oO!! ou seja, o objeto é preenchido, e depois o JSF, sabe lá deus porque, joga zero no campo, entenderam?

Segue, abaixo os códigos para, quem puder dar uma olhada: (Os dados e os converters estão “hardcode”, para o exemplo ser testável.

As entidades Estado e Cidade:

package br.com.webdoc.modelo;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

public class Estado implements Serializable {

	private static final long serialVersionUID = -8247490375284146948L;
	
	private long id;
	private String nome;
	private List<Cidade> cidades;
	
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
	public String getNome() {
		return this.nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	
	public List<Cidade> getCidades() {
		return this.cidades;
	}
	
	public Estado() {
		this.cidades = new ArrayList<Cidade>();
	}
	public Estado(long id) {
		this();
		this.setId(id);
	}
	public Estado(long id, String nome) {
		this(id);
		this.setNome(nome);
	}
	
	@Override
	public boolean equals(Object obj) {
		 
		if (obj instanceof Estado) {
			
			Estado estado = (Estado) obj;
			
			return (estado.getId() == this.getId());
		}
		return false;
	}
	public int hashCode() {
		return 0;
	}
}

package br.com.webdoc.modelo;

import java.io.Serializable;

public class Cidade implements Serializable {

	static final long serialVersionUID = 6905091574203767022L;


	private long id;
	private String nome;	
	private int valorComp;
	private int diasComp;


	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
	public String getNome() {
		return this.nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	
	public int getValorComp() {
		return valorComp;
	}
	public void setValorComp(int valorComp) {
		this.valorComp = valorComp;
	}
	
	public Integer getDiasComp() {
		return diasComp;
	}
	public void setDiasComp(Integer diasComp) {
		this.diasComp = diasComp;
	}


	public Cidade() {
		this.valorComp = 0;
		this.diasComp = 0;		
	}
	public Cidade(long id) {
		this();
		this.setId(id);
	}
	public Cidade(long id, String nome) {
		this(id);
		this.setNome(nome);
	}
	public Cidade(long id, String nome, int valorComp, int diasComp) {
		this(id, nome);
		this.setValorComp(valorComp);
		this.setDiasComp(diasComp);
	}

	@Override
	public boolean equals(Object obj) {
		 
		if (obj instanceof Cidade) {
			
			Cidade cidade = (Cidade) obj;
			
			return (cidade.getId() == this.getId());
		}
		return false;
	}
	public int hashCode() {
		return 0;
	}
}

os Converters:

package br.com.webdoc.converters;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

import br.com.webdoc.modelo.Estado;

public class EstadoConverter implements Converter {

	public Object getAsObject(FacesContext context, UIComponent component, String value) {

		Estado estado = null;

		if (value != null) {

			estado = new Estado(new Long(value));
		}

		return estado;
	}

	public String getAsString(FacesContext context, UIComponent component, Object value) {

		long id = 0;

		if (value instanceof Estado) {

			Estado estado = (Estado) value;

			id = estado.getId();
		}

		return String.valueOf(id);
	}
}

package br.com.webdoc.converters;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;

import br.com.webdoc.modelo.Cidade;

public class CidadeConverter implements Converter {

	public Object getAsObject(FacesContext context, UIComponent component, String value) {

		Cidade cidade = null;

		if (value != null) {
			
			cidade = new Cidade();
			cidade.setId(new Long(value.split(",")[0]));
			cidade.setNome(value.split(",")[1]);
			cidade.setDiasComp(new Integer(value.split(",")[2]));
			cidade.setValorComp(new Integer(value.split(",")[3]));
		}

		return cidade;
	}

	public String getAsString(FacesContext context, UIComponent component, Object value) {

		String cidadeString = "";

		if (value instanceof Cidade) {

			Cidade cidade = (Cidade) value;

			cidadeString = String.valueOf(cidade.getId()) + ",";
			cidadeString += cidade.getNome() + ",";
			cidadeString += cidade.getDiasComp() + ",";
			cidadeString += cidade.getValorComp();
		}

		return cidadeString;
	}
}

o managedbean

package br.com.webdoc.handlers;

import java.util.ArrayList;
import java.util.List;

import javax.faces.component.html.HtmlSelectOneMenu;
import javax.faces.event.ValueChangeEvent;
import javax.faces.model.SelectItem;

import br.com.webdoc.modelo.Cidade;
import br.com.webdoc.modelo.Estado;

public class EstadosCidadesHandler {

	// membros privados
	private HtmlSelectOneMenu mnuEstados = new HtmlSelectOneMenu();
	private HtmlSelectOneMenu mnuCidades = new HtmlSelectOneMenu();
	private List<SelectItem> estados = null;
	private List<SelectItem> cidades = null;
	private Cidade cidade = null;
	
	
	// getters/setters
	public HtmlSelectOneMenu getMnuEstados() {
		return mnuEstados;
	}
	public void setMnuEstados(HtmlSelectOneMenu mnuEstados) {
		this.mnuEstados = mnuEstados;
	}
	public HtmlSelectOneMenu getMnuCidades() {
		return this.mnuCidades;
	}
	public void setMnuCidades(HtmlSelectOneMenu mnuCidades) {
		this.mnuCidades = mnuCidades;
	}
	public List<SelectItem> getEstados() {
		
		if(this.estados == null) {
			
			this.estados = new ArrayList<SelectItem>();
			
			Estado estado = new Estado(0);
			estado.setNome("Selecione um Estado");
			this.estados.add(new SelectItem(estado, estado.getNome()));
			
			estado = new Estado(1, "São Paulo");
			estado.getCidades().add(new Cidade(1, "São Paulo", 11, 11));
			estado.getCidades().add(new Cidade(2, "Campinas", 22, 22));
			estado.getCidades().add(new Cidade(3, "São Carlos", 33, 33));
			estado.getCidades().add(new Cidade(4, "Americana", 33, 33));
			this.estados.add(new SelectItem(estado, estado.getNome()));
			
			estado = new Estado(2, "Rio de Janeiro");
			estado.getCidades().add(new Cidade(5, "Rio de Janeiro", 44, 44));
			estado.getCidades().add(new Cidade(6, "Trindade", 55, 55));
			estado.getCidades().add(new Cidade(7, "Campos dos Goytacazes", 66, 66));
			estado.getCidades().add(new Cidade(8, "Barra Mansa", 77, 77));
			this.estados.add(new SelectItem(estado, estado.getNome()));
			
			estado = new Estado(3, "Minas Gerais");
			estado.getCidades().add(new Cidade(9, "Belo Horizonte", 88, 88));
			estado.getCidades().add(new Cidade(10, "Itajuba", 99, 99));
			estado.getCidades().add(new Cidade(11, "Rio Claro", 10, 10));
			this.estados.add(new SelectItem(estado, estado.getNome()));
			
			estado = new Estado(4, "Bahia");
			estado.getCidades().add(new Cidade(13, "Salvador", 11, 11));
			estado.getCidades().add(new Cidade(14, "Abaira", 12, 12));
			estado.getCidades().add(new Cidade(15, "Antas", 13, 13));
			estado.getCidades().add(new Cidade(16, "Aracas", 14, 14));
			this.estados.add(new SelectItem(estado, estado.getNome()));
			
			estado = new Estado(5, "Ceará");
			estado.getCidades().add(new Cidade(17, "Fortaleza", 15, 15));
			estado.getCidades().add(new Cidade(18, "Abaiara", 16, 16));
			this.estados.add(new SelectItem(estado, estado.getNome()));
		}
		
		return estados;
	}
	
	
	// metodos privados
	public List<SelectItem> getCidades() {
		
		if(this.cidades == null) {
			
			this.cidades = new ArrayList<SelectItem>();
			
			Cidade cidade = new Cidade();
			cidade.setId(0);
			cidade.setNome("Selecione uma Cidade");
			this.cidades.add(new SelectItem(cidade, cidade.getNome()));
		}
		
		return cidades;
	}
	public Cidade getCidade() {
		return cidade;
	}
	public void setCidade(Cidade cidade) {
		this.cidade = cidade;
	}
	
	
	// metodos publicos
	public void carregarCidades(ValueChangeEvent event) {
		
		if(event.getComponent().equals(this.mnuEstados)) {

			this.cidade = new Cidade();
			this.cidades = new ArrayList<SelectItem>();
			
			Cidade cidadeFake = new Cidade();
			cidadeFake.setId(0);
			cidadeFake.setNome("Selecione uma Cidade");
			this.cidades.add(new SelectItem(cidadeFake, cidadeFake.getNome()));
			
			Estado estadoSelecionado =  this.carregarEstado(((Estado)event.getNewValue()).getId());
			for (Cidade cidade : estadoSelecionado.getCidades()) {
				
				this.cidades.add(new SelectItem(cidade, cidade.getNome()));
			}
		}
	}
	
	private Estado carregarEstado(long id) {
		
		Estado estado = null;
		
		for (SelectItem item : this.estados) {
			
			if(((Estado)item.getValue()).getId() == id) {
				
				estado = (Estado)item.getValue();
				break;
			}
		}
		
		return estado;
	}
	
	public void exibirDados(ValueChangeEvent e) {
		
		if(e.getComponent().equals(this.mnuCidades)) {
			
			this.cidade = new Cidade();
			this.cidade = (Cidade)this.mnuCidades.getValue();
		}
	}
}

a JSP:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<f:view>
	<h:form id="pessoaForm">
		<html>
			<head>
				<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
				<title>Insert title here</title>
			</head>
			<body>
				<h:messages />
				<h:outputText value="Estados:" />
				<h:selectOneMenu binding="#{estadosCidadesHandler.mnuEstados}"
								 valueChangeListener="#{estadosCidadesHandler.carregarCidades}"
								 onchange="submit();"
								 immediate="true">
					<f:selectItems value="#{estadosCidadesHandler.estados}"/>
					<f:converter converterId="estadoConverter" />
				</h:selectOneMenu>
				<br />
				<h:outputText value="Cidades:" />
				<h:selectOneMenu binding="#{estadosCidadesHandler.mnuCidades}"
								 valueChangeListener="#{estadosCidadesHandler.exibirDados}"
								 onchange="submit();"
								 immediate="true">
					<f:selectItems value="#{estadosCidadesHandler.cidades}"/>
					<f:converter converterId="cidadeConverter" />
				</h:selectOneMenu>
				<br /><br /><br />
				<h:outputLabel value="Valor Comp:" />
				<h:inputText value="#{estadosCidadesHandler.cidade.valorComp}" />
				<br />
				<h:outputLabel value="Dias Comp:" />
				<h:inputText value="#{estadosCidadesHandler.cidade.diasComp}" />
			</body>
		</html>
	</h:form>
</f:view>

e as partes relevantes do faces-config:

      <managed-bean>
		<managed-bean-name>estadosCidadesHandler</managed-bean-name>
		<managed-bean-class>
			br.com.webdoc.handlers.EstadosCidadesHandler
		</managed-bean-class>
		<managed-bean-scope>session</managed-bean-scope>
	</managed-bean>

	<converter>
		<converter-id>cidadeConverter</converter-id>
		<converter-class>br.com.webdoc.converters.CidadeConverter</converter-class>
	</converter>

	<converter>
		<converter-id>estadoConverter</converter-id>
		<converter-class>br.com.webdoc.converters.EstadoConverter</converter-class>
	</converter>

Alguem já passou por algum problema parecido ou tem alguma idéia do que possa estar acontecendo?

Muito obrigado turma!

Oi Rogério!

Não se entendi o problema direito…
Você quer escolher o estado e a cidade e carregar os dois campos da cidade logo depois, é isso? E o que não está funcionando é a exibição desses dados?

Eu chutaria que o problema é no ValueChangeListener da cidade. Como ele ta immediate, é executado antes da fase “apply request values”. Aí isso carrega a cidade mas depois na hora de aplicar os valores do form, como ainda tá em branco, ele zera a cidade.

Tenta fazer o seguinte: no final dos métodos de listener, chame o metodo renderResponse() no FacesContext. Isso pula a execução das outras fases…

[]'s
Sérgio

[quote=rogerio.alcantara][/quote]
eae rogerio, td bem??

Sei que o post é antigo, mas gostaria de saber se vc conseguiu resolver teu problema… e se possível, postar a solução.

Agradeço.