Erro de validação: o valor não é válido

Já implementei ‘equals’ e ‘hashCode’ (gerados pelo próprio Eclipse) e também o converter.

Esse “Erro de validação: o valor não é válido” só acontece AS VEZES e eu não faço a menor ideia de como resolver isso (já pensei que pode ser algum bug do JSF). Quando seleciono algum país do combobox o erro já aparece (repito, esse erro só acontece AS VEZES).

Esse AS VEZES que está me impossibilitando de resolver o problema. Se fosse algo que sempre acontecesse, até teria lógica…

Abaixo disponibilizo os fontes. Por favor, quem puder me ajudar ficarei muito grato.

					 <p:outputLabel for="pais" value="País:" />
					 <p:selectOneMenu id="pais" value="#{clienteController.pais}" >
						<f:selectItem itemLabel="Selecione..." itemValue="" />
						<f:selectItems value="#{clienteController.paises}" var="p" itemLabel="#{p.nome}" itemValue="#{p}"/>						
						<p:ajax event="change" listener="#{clienteController.actionCarregaUfs}" update="uf" />
					 </p:selectOneMenu>
package control;

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

import dao.PaisDao;
import dao.PaisDaoImp;

import model.Pais;

@FacesConverter(forClass=Pais.class)
public class PaisConverter implements Converter {

	@Override
	public Object getAsObject(FacesContext arg0, UIComponent arg1, String value) {		
		if (value != null && !value.equals("")) {
			PaisDao paisDao = new PaisDaoImp();
			return paisDao.findById(Integer.valueOf(value));
		}
		return null;
	}

	@Override
	public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
		if (value instanceof Pais) {
			Pais pais = (Pais) value;	
			return String.valueOf(pais.getCodigo());
		}
		return "";
	}

	
	
}
package control;

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

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.faces.model.SelectItem;

import dao.ClienteDao;
import dao.ClienteDaoImp;
import dao.PaisDaoImp;
import dao.TipoDocumentoDaoImp;
import dao.UnidadeFederacaoDaoImp;

import model.Cliente;
import model.Municipio;
import model.Pais;
import model.TipoDocumento;
import model.UnidadeFederacao;

@ManagedBean
@ViewScoped
public class ClienteController implements Serializable {
	
	private Cliente cliente;
	private DataModel listaClientes;
	private List<Cliente> filteredClientes;
	private Boolean isInsercao;
	private Boolean isAlteracao;
	
	private Pais pais;
	private List<Pais> paises;
	private List<UnidadeFederacao> ufs;	
	private UnidadeFederacao uf;
	private List<Municipio> municipios;
	
	private List<TipoDocumento> tiposDocumentos;
		
	public ClienteController() {
		this.cliente = new Cliente();
		this.pais = new Pais();
		this.ufs = new ArrayList<UnidadeFederacao>();
		this.uf = new UnidadeFederacao();
		this.municipios = new ArrayList<Municipio>();
		this.tiposDocumentos  = new ArrayList<TipoDocumento>();
	}

	public List<Cliente> getFilteredClientes() {
		return filteredClientes;
	}

	public void setFilteredClientes(List<Cliente> filteredClientes) {
		this.filteredClientes = filteredClientes;
	}

	public DataModel getListarClientes() {
		List<Cliente> lista = new ClienteDaoImp().list();
		listaClientes = new ListDataModel(lista);
		return listaClientes;
	}

	public Cliente getCliente() {
		return cliente;
	}

	public void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	public String prepararAdicionarCliente() {
		cliente = new Cliente();
		isInsercao = true;
		isAlteracao = false;				
		return "gerenciarCliente";
	}

	public String prepararAlterarCliente() {
		isInsercao = false;
		isAlteracao = true;
		this.pais = this.cliente.getMunicipio().getUf().getPais();
		this.uf = this.cliente.getMunicipio().getUf();
		return "gerenciarCliente";
	}

	public String excluirCliente() {
		Cliente clienteTemp = (Cliente) (listaClientes.getRowData());
		ClienteDao dao = new ClienteDaoImp();
		dao.remove(clienteTemp);
		return "index";
	}
	
	public String actExcluirCliente() {
		ClienteDao dao = new ClienteDaoImp();
		dao.remove(cliente);
		return "index";
	}	

	public String adicionarCliente() {
		System.out.println("Adicionando Cliente...");
		ClienteDao dao = new ClienteDaoImp();
		dao.save(cliente);
		return "index";
	}

	public String alterarCliente() {
		ClienteDao dao = new ClienteDaoImp();
		dao.update(cliente);
		return "index";
	}

	public Boolean getIsInsercao() {
		return isInsercao;
	}

	public void setIsInsercao(Boolean insercao) {
		this.isInsercao = insercao;
	}

	public Boolean getIsAlteracao() {
		return isAlteracao;
	}

	public void setIsAlteracao(Boolean alteracao) {
		this.isAlteracao = alteracao;
	}
	
		
	/**************************************************/
	
	
	public Pais getPais() {
		return pais;
	}

	public void setPais(Pais pais) {
		this.pais = pais;
	}

	public List<Pais> getPaises() {
		paises = new PaisDaoImp().list();
		return paises;
	}

	public void setPaises(List<Pais> paises) {
		this.paises = paises;
	}

	public List<UnidadeFederacao> getUfs() {
		return ufs;
	}

	public void setUfs(List<UnidadeFederacao> ufs) {
		this.ufs = ufs;
	}

	public UnidadeFederacao getUf() {
		return uf;
	}

	public void setUf(UnidadeFederacao uf) {
		this.uf = uf;
	}

	public List<Municipio> getMunicipios() {
		return municipios;
	}

	public void setMunicipios(List<Municipio> municipios) {
		this.municipios = municipios;
	}

	public List<UnidadeFederacao> getUfsByPais() {							
		ufs = new PaisDaoImp().getUFsByPais(this.pais.getCodigo());
		return ufs;
	}	
	
	public void actionCarregaUfs() {
		ufs.clear();
		if (this.pais != null) {
			if (!String.valueOf(this.pais.getCodigo()).equals("")) {
				this.getUfsByPais();			
			}
		}										
	}
	
	public List<Municipio> getMunicipiossByUf() {							
		municipios = new UnidadeFederacaoDaoImp().getMunicipiosByUF(this.uf.getCodigo());
		return municipios;
	}	
	
	public void actionCarregaMunicipios() {
		municipios.clear();
		try {
			this.uf.getCodigo();
		} catch(NullPointerException e) {
			return;
		}		
		this.getMunicipiossByUf();
	}		
	
	public List<TipoDocumento> getTiposDocumentos() {
		tiposDocumentos = new TipoDocumentoDaoImp().list();
		return tiposDocumentos;
	}	

}
package model;

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

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "pais")
public class Pais implements Serializable {

	@Id
	@Column(name = "id_pais")
	private Integer codigo;
	@Column(length = 4)
	private String sigla;
	private String nome;
	@OneToMany(mappedBy = "pais")
	private List<UnidadeFederacao> unidadesFederacao;

	public Pais() {
	}

	public Object getId() {
		return nome;
	}

	public Integer getCodigo() {
		return codigo;
	}

	public void setCodigo(Integer codigo) {
		this.codigo = codigo;
	}

	public String getSigla() {
		return sigla;
	}

	public void setSigla(String sigla) {
		this.sigla = sigla;
	}

	public String getNome() {
		return nome;
	}

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

	public List<UnidadeFederacao> getUnidadesFederacao() {
		return unidadesFederacao;
	}

	public void setUnidadesFederacao(List<UnidadeFederacao> unidadesFederacao) {
		this.unidadesFederacao = unidadesFederacao;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((codigo == null) ? 0 : codigo.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Pais))
			return false;
		Pais other = (Pais) obj;
		if (codigo == null) {
			if (other.codigo != null)
				return false;
		} else if (!codigo.equals(other.codigo))
			return false;
		return true;
	}	
	
}

Ao iterar uma lista de um tipo de objeto, é necessário passar por um converter para retornar o tipo certo do objeto.

Dá uma olhada nesse post do BalusC:

Eu já fiz desse jeito que o site que você passou está mostrando… tentei criar um método que retornasse um List, mas o erro acontece do mesmo jeito.

Já deu uma olhada no começo da sua página se tem

<?xml version="1.0" encoding="ISO-8859-1" ?>

Já problemas de erro de validação por causa da codificação não reconhecer os acentos. Tive esse problema com selectOne’s combinados de Estado > Cidade, por causa dos acentos em estados como Paraná, São Paulo, etc.

Mesmo se o SelectOneMenu não retornar nenhuma palavra com acento?
Enfim, eu adicionei o <?xml version="1.0" encoding="ISO-8859-1" ?> e agora estou fazendo alguns testes… qualquer coisa eu retorno ao tópico.

Meus testes não demoraram muito.
Tentei a primeira vez, funcionou… tentei a segunda vez, funcionou… na terceira vez o mesmo erro voltou a aparecer: País:: Erro de validação: o valor não é válidoPaís:: Erro de validação: o valor não é válido

Ficarei eternamente grato se alguém conseguir me ajudar a resolver isso.

Nesse caso, sugiro arrumar teu hascode e equals, deixando explicito quando um país é igual a outro, por exemplo:

 @Override  
    public int hashCode() {  
        return (codigo == null) ? 0 : codigo;
    }  
  
    @Override  
    public boolean equals(Object obj) {  
        if (obj == null)  return false;  
        if (obj instanceof Pais)){
            return ((Pais)obj).getCodigo().equals(this.codigo);  
        }
        return false;  
    } 

Na fase de validação do JSF a implementação chama o método equals do seu objeto para garantir que o objeto que está sendo passado é o mesmo foi enviado para a view.

Tenta ai e retorna aqui se deu certo.

Uma curiosidade tbm uso dessa forma e estou tendo praticamente o mesmo problema, eu sou obrigado a implementar o tostring e o equals nos meus pojos?

Guilherme, não quero me animar muito, mas implementando o ‘equals’ do jeito que você me orientou parece que o erro não ocorre mais. Pelo menos por enquanto não ocorreu mais. Eu vou continuar fazendo testes por mais um tempo mas a princípio está OK.

Valeu, meu amigo! Qualquer coisa eu retorno ao tópico.

Chaapolinn, se estiver utilizando JSF, para utilizar seus objetos em um SelectOne por exemplo vai ter que implementar o hashcode e equals, o tostring não é necessário.

estranho é que não implementei e funcionou certinho. pq Será?

Aproveitando o tópico… alguém sabe explicar o porquê do ‘equals’ que eu havia implementado funcionava apenas na maioria dos casos e de uma hora pra outra deixava de funcionar ocasionando o “value is not valid”?

[quote=guilherme_costa]Nesse caso, sugiro arrumar teu hascode e equals, deixando explicito quando um país é igual a outro, por exemplo:

 @Override  
    public int hashCode() {  
        return (codigo == null) ? 0 : codigo;
    }  
  
    @Override  
    public boolean equals(Object obj) {  
        if (obj == null)  return false;  
        if (obj instanceof Pais)){
            return ((Pais)obj).getCodigo().equals(this.codigo);  
        }
        return false;  
    } 

Na fase de validação do JSF a implementação chama o método equals do seu objeto para garantir que o objeto que está sendo passado é o mesmo foi enviado para a view.

Tenta ai e retorna aqui se deu certo.[/quote]

Cara, estava com um problema semelhante!
Esse código do hashcode e equals resolveu pra mim! Perfeito!