Erro de validação selectOneMenu[RESOLVIDO]

Galera, sei que estou sendo muuuiiito redundante e que existem uns 1300 post sobre o assunto, mas eu já testei inúmeras possibilidades e nada…
Meu problema é o seguinte:
Tenho um cadastro de administrador, sempre que um determinado estado é selecionado, todas as cidades são carregadas. Essa parte está OK. O problema é quando eu tento salvar os dados. Eu recebo a seguinte mensagem de erro “cadastro:cidade: Erro de validação: o valor não é válido”.
Eu já fiz vários teste e li diversos posts…como nada funcionou, acho que o erro eh uma babaquice no meu código, portanto vou listar aqui o código de todas as classes.

Alguém pode me ajudar???

Classe Cidade:

package sistemasas.endereco;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
import javax.validation.constraints.NotNull;

@Entity
@Table
@org.hibernate.annotations.Entity(
	dynamicInsert=true, dynamicUpdate=true
)
public class Cidade implements Serializable {

    private static final long serialVersionUID = -3026742356598641437L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column
    private int id;
    
    @Column(nullable=false, length=50)
    private String nome;

    @ManyToOne(fetch=FetchType.EAGER)
    @JoinColumn(name="estado", nullable=false)
    @NotNull(message="Informe o estado")    
    private Estado estado;
    
    public int getId() {
        return id;
    }

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

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }
       
    public Estado getEstado() {
        return estado;
    }

    public void setEstado(Estado estado) {
        this.estado = estado;
    }

    @Override
    public boolean equals(Object obj) {

	if (this == obj) {
	    return true;
	}
	
	if (!(obj instanceof Cidade)) {
	    return false;
	}
	
	Cidade cidadeInformada = (Cidade) obj;
	
	return (cidadeInformada.getId() == this.id);
	
    }

    @Override
    public int hashCode() {

	int hash = 7;
	
	hash = 97 * hash + (this.id != 0 ? this.id : 0); 
	
	return hash;
	
	//return this.id == 0 ? System.identityHashCode(this) : this.id;
	
    }
        
}

Classe Estado

package sistemasas.endereco;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table
@org.hibernate.annotations.Entity(
	dynamicInsert=true, dynamicUpdate=true
)
public class Estado implements Serializable {

    private static final long serialVersionUID = -465065416573825390L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column    
    private int id;
    
    @Column(nullable=false, columnDefinition="char(2)")    
    private String uf;
    
    @Column(nullable=false, length=50)
    private String nome;

    public int getId() {
        return id;
    }
    
    public void setId(int id) {
        this.id = id;
    }
    
    public String getUf() {
        return uf;
    }
    
    public void setUf(String uf) {
        this.uf = uf;
    }
    
    public String getNome() {
        return nome;
    }
    
    public void setNome(String nome) {
        this.nome = nome;
    }

    @Override
    public boolean equals(Object obj) {

	if (this == obj) {
	    return true;
	}
	
	if (!(obj instanceof Estado)) {
	    return false;
	}
	
	Estado estadoInformado = (Estado) obj;
	
	return (estadoInformado.getId() == this.id);
	
    }

    @Override
    public int hashCode() {

	int hash = 5;
	
	hash = 41 * hash + (this.id != 0 ? this.id : 0); 
	
	return hash;	
	
	//return this.id == 0 ? System.identityHashCode(this) : this.id;
	
    }
    

    
}

Classe AdministradorBean

package skymedic.administrador;

import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
import javax.faces.event.ValueChangeEvent;

import sistemasas.administrador.Administrador;
import sistemasas.administrador.AdministradorBusiness;
import sistemasas.administrador.AdministradorValidaAtributos;
import sistemasas.endereco.Cidade;
import sistemasas.endereco.Estado;
import sistemasas.endereco.ICidadeDAO;
import sistemasas.endereco.IEstadoDAO;
import sistemasas.pessoa.IPessoaDAO;
import sistemasas.pessoa.Pessoa;
import sistemasas.utils.mensagem.FormataMensagem;
import skymedic.endereco.EnderecoFactory;
import skymedic.pessoa.PessoaFactory;
import skymedic.utils.ExibeMensagem;

@ManagedBean(name="adminBean")
@RequestScoped
public class AdministradorBean {

    private final String PAGINA_ADMIN_CADASTRO = "admincadastro";
    private final String PAGINA_ADMIN_EDICAO = "/admin/admincadastro";
    private final String PAGINA_ADMIN_LISTA = "adminlista";    
    
    private Administrador administrador;
    private List<Administrador> administradores;
    private List<Administrador> administradoresConsultados;
    
    private List<Estado> estadosCadastrados;
    private Estado estadoSelecionado;

    private List<Cidade> cidades;    
    private Cidade cidadeSelecionada;

    public AdministradorBean() {
	
	this.administrador = AdministradorFactory.criarAdministrador();
	this.administrador.setPessoa(PessoaFactory.criarPessoa());
	
    }
          
    public Administrador getAdministrador() {
        return administrador;
    }

    public void setAdministrador(Administrador administrador) {
        this.administrador = administrador;
    }
    
   
    public List<Administrador> getAdministradoresConsultados() {
        return administradoresConsultados;
    }

    public void setAdministradoresConsultados(List<Administrador> administradoresConsultados) {
        this.administradoresConsultados = administradoresConsultados;
    }
       
    public List<Estado> getEstadosCadastrados() {
	
	if (this.estadosCadastrados == null) {
	    
	    IEstadoDAO estadoDAO = EnderecoFactory.criarEstadoDAO();
	    this.estadosCadastrados = estadoDAO.listar();
	    
	}
	
        return estadosCadastrados;
    }

    public void setEstadosCadastrados(List<Estado> estadosCadastrados) {
        this.estadosCadastrados = estadosCadastrados;
    }

    public Estado getEstadoSelecionado() {
	
	if (administradorPossuiEstado()) {
	    
	    this.estadoSelecionado = this.administrador.getPessoa().getEstado();
	    
	}
	
        return estadoSelecionado;
    }
    
    private boolean administradorPossuiEstado() {
	
	return (this.administrador.getPessoa().getEstado() != null);
	
    }

    public void setEstadoSelecionado(Estado estadoSelecionado) {
        this.estadoSelecionado = estadoSelecionado;
    }
        
    public Cidade getCidadeSelecionada() {		
	
	if (administradorPossuiCidade()) {
	    
	    this.cidadeSelecionada = this.administrador.getPessoa().getCidade();
	    
	}
	
        return cidadeSelecionada;
    }
    
    public boolean administradorPossuiCidade() {
	
	return (this.administrador.getPessoa().getCidade() != null);
	
    }

    public void setCidadeSelecionada(Cidade cidadeSelecionada) {
        this.cidadeSelecionada = cidadeSelecionada;
    }

    public List<Cidade> getCidades() {	
        return this.cidades;
    }

    public void setCidades(List<Cidade> cidades) {
        this.cidades = cidades;
    }

    public List<Administrador> getListagem() {
	
	if (this.administradores == null) {
	    
	    AdministradorBusiness admBusiness = AdministradorFactory.criarAdministradorBusiness();
	    this.administradores = admBusiness.listar();
	    
	}
	
	return this.administradores;
	
    }
    
    public String novo() {
	
	return PAGINA_ADMIN_CADASTRO;
	
    }
    
    public String editar() {
	
	return PAGINA_ADMIN_EDICAO;
	
    }

    public String salvar() {
	
	try {
	    
	    definirEstado();
	    
	    definirCidade();
	    
	    validarAtributos();
	    
	    AdministradorBusiness adminBusiness = AdministradorFactory.criarAdministradorBusiness();
	    adminBusiness.salvar(this.administrador);
	    
	    ExibeMensagem.exibirMensagemOK("Administrador gravado com sucesso");
	    
	    return PAGINA_ADMIN_LISTA;
	    
	} catch(Exception e) {
	    
	    ExibeMensagem.exibirMensagemErro(e.getMessage(), "");
	    
	}
	
	return null;
	
    }
    
    public String excluir() {
	
	try {
	    
	    AdministradorBusiness adminBusiness = AdministradorFactory.criarAdministradorBusiness();
	    adminBusiness.excluir(this.administrador);
	    
	    this.administradores = null;
	    
	    ExibeMensagem.exibirMensagemOK("Administrador excluido com sucesso");
	    
	    return PAGINA_ADMIN_LISTA;
	    
	} catch(Exception e) {
	    
	    ExibeMensagem.exibirMensagemErro(e.getMessage(), "");
	    
	}
	
	return null;
	
    }
    
    public void validarAtributos() throws Exception {

	AdministradorValidaAtributos validador = AdministradorFactory.criarAdministradorValidaAtributos();
	
	List<String> erros = validador.validarAtributos(this.administrador);
	
	if (! erros.isEmpty()) {
	    
	    FormataMensagem msg = new FormataMensagem();
		
	    msg.addMensagens(erros);	    
	    
	    throw new Exception(msg.getMensagens());
	}	
	
    }
    
    public void carregarDadosPessoa() {		
	
	String documento = this.administrador.getPessoa().getDocumento();
	
	if (documento!= null && ! "".equals(documento)) {
	    
	    IPessoaDAO pessoaDAO = PessoaFactory.criarPessoaDAO();
	    Pessoa pessoa = pessoaDAO.buscarPeloDocumento(documento);
	    
	    if (pessoa != null) {
		
		this.administrador.setPessoa(pessoa);
		this.estadoSelecionado = pessoa.getEstado();
		this.cidadeSelecionada = pessoa.getCidade();
		
	    }
	    	    
	}

    }
    
    public void definirEstado() {
	
	if (this.estadoSelecionado != null) {
	    
	    this.administrador.getPessoa().setEstado(this.estadoSelecionado);
	    
	}
	
	
    }
    
    public void definirCidade() {
	
	if (this.cidadeSelecionada != null) {
	    
	    this.administrador.getPessoa().setCidade(this.cidadeSelecionada);
	    
	}
	
    }
    
    public void carregarCidades(ValueChangeEvent evento) {	
		
	Object obj = evento.getNewValue();
	
	if (obj instanceof Estado) {
	    
	    Estado estado = (Estado) obj;
	    
	    ICidadeDAO cidadeDAO = EnderecoFactory.criarCidadeDAO();
	    this.cidades = cidadeDAO.listar(estado);
	    
	}	
	
    }
            
}

Classe CidadeConverter

package skymedic.endereco;

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

import sistemasas.endereco.Cidade;
import sistemasas.endereco.ICidadeDAO;

@FacesConverter(forClass= Cidade.class, value="cidadeConverter")
public class CidadeConverter  implements Converter {

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

	if (value != null && value.trim().length() > 0) {
	    
	    int id = Integer.valueOf(value.trim());
	    
	    try {
        	
		ICidadeDAO cidadeDAO = EnderecoFactory.criarCidadeDAO();
        	Cidade cidade = cidadeDAO.buscar(id);
        	
        	if (cidade == null) {
        	    throw new Exception("Nenhuma cidade retornada");
        	}
        	
        	return cidade;
        	        	
	    } catch(Exception e) {
		
		FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro ao carregar cidade", "Nenhuma cidade encontrada");  
		throw new ConverterException(msg);
		
	    }
	}
	
	return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) {

	if (object != null && ! "".equals(object)) {
	    
	    Cidade cidade = (Cidade) object;
	    return String.valueOf(cidade.getId());
	    
	}
	
	return "";
    }    
    
}

Classe EstadoConverter

package skymedic.endereco;

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

import sistemasas.endereco.Estado;
import sistemasas.endereco.IEstadoDAO;

@FacesConverter(forClass= Estado.class, value="estadoConverter")
public class EstadoConverter implements Converter {

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

	if (value != null && value.trim().length() > 0) {
	    
	    int id = Integer.valueOf(value.trim());
	    
	    try {
        	
		IEstadoDAO estadoDAO = EnderecoFactory.criarEstadoDAO();
        	Estado estado = estadoDAO.buscar(id);
        	
        	if (estado == null) {
        	    throw new Exception("Nenhum estado retornado");
        	}
        	
        	return estado;
        	        	
	    } catch(Exception e) {
		
		FacesMessage msg = new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erro ao carregar estado", "Nenhum estado encontrado");  
		throw new ConverterException(msg);
		
	    }
	}
	
	return null;
    }

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object object) {

	if (object != null && ! "".equals(object)) {
	    
	    Estado estado = (Estado) object;
	    return String.valueOf(estado.getId());
	    
	}
	
	return "";
    }

}

admincadastro.xhtml

<?xml version="1.0" encoding="ISO-8859-1" ?>
<!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"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:p="http://primefaces.org/ui"
>

<ui:composition template="/template/admintemplate.xhtml">
	<ui:define name="conteudo">
			   		
		<p:panel header="Cadastro de Administrador">
			
			<h:outputScript library="scripts" name="somentenumeros.js" />
			
			<h:form id="cadastro">
				
				<h:inputHidden id="adminid" value="#{adminBean.administrador.id}"/>
				<h:inputHidden id="pessoaid" value="#{adminBean.administrador.pessoa.id}"/>
				
				<p:messages id="mensagens" showDetail="false" autoUpdate="true" closable="true"/>
				
				<h:panelGrid columns="2">

					<h:outputLabel value="Documento *" for="documento"/>
					<p:inputText id="documento" value="#{adminBean.administrador.pessoa.documento}"
						size="14" maxlength="14" required="true" requiredMessage="Informe o número do documento"
						onkeypress="return somenteNumero(event);">
						<p:ajax event="change" update="pessoaid, nome, logradouro, numero, complemento, bairro, estado, cidade,
							cep, telefone1, telefone2, email"
							listener="#{adminBean.carregarDadosPessoa}"></p:ajax>
					</p:inputText> 					

					<h:outputLabel value="Nome *" for="nome"/>
					<p:inputText id="nome" value="#{adminBean.administrador.pessoa.nome}"
						size="100" maxlength="100" required="true" requiredMessage="Informe o nome">
					</p:inputText>
					  
					<h:outputLabel value="Logradouro *" for="logradouro"/>
					<p:inputText id="logradouro" value="#{adminBean.administrador.pessoa.logradouro}"
						size="100" maxlength="100" required="true" requiredMessage="Informe o logradouro">
					</p:inputText>
					
					<h:outputLabel value="Número" for="numero"/>
					<p:inputText id="numero" value="#{adminBean.administrador.pessoa.numero}"
						size="20" maxlength="20" required="false">
					</p:inputText>
					
					<h:outputLabel value="Complemento" for="complemento"/>
					<p:inputText id="complemento" value="#{adminBean.administrador.pessoa.complemento}"
						size="20" maxlength="20" required="false">
					</p:inputText>

					<h:outputLabel value="Estado *" for="estado"/>
					<p:selectOneMenu id="estado"		
						valueChangeListener="#{adminBean.carregarCidades}"				 
						value="#{adminBean.estadoSelecionado}" 
						converter="estadoConverter" 
						effect="fade" style="width:160px"
						required="true" requiredMessage="Selecione um estado">  						
						<f:selectItem itemLabel="Selecione um estado" itemValue="" />  
						<f:selectItems value="#{adminBean.estadosCadastrados}" var="estado" 
							itemLabel="#{estado.nome}" itemValue="#{estado}"/>  						
						<p:ajax event="change"  update="cidade"/>												
					</p:selectOneMenu>																																 

					<h:outputLabel value="Cidade *" for="cidade"/>
					<p:selectOneMenu id="cidade" 
						value="#{adminBean.cidadeSelecionada}" 
						converter="cidadeConverter" 
						effect="fade" style="width:160px"
						required="true" requiredMessage="Selecione uma cidade">  						
						<f:selectItem itemLabel="Selecione uma cidade" itemValue="" />  
						<f:selectItems value="#{adminBean.cidades}" var="cidade" itemLabel="#{cidade.nome}" itemValue="#{cidade}"/>						  												  					
					</p:selectOneMenu>													
					
					<h:outputLabel value="Bairro *" for="bairro"/>
					<p:inputText id="bairro" value="#{adminBean.administrador.pessoa.bairro}"
						size="50" maxlength="50" required="true" requiredMessage="Informe o bairro">
					</p:inputText>					
							
					<h:outputLabel value="CEP" for="cep"/>
					<p:inputText id="cep" value="#{adminBean.administrador.pessoa.cep}"
						size="8" maxlength="8" required="false" requiredMessage="Informe o CEP">
					</p:inputText>

					<h:outputLabel value="Telefone 1" for="telefone1"/>
					<p:inputText id="telefone1" value="#{adminBean.administrador.pessoa.telefone1}"
						size="10" maxlength="10" required="false">
					</p:inputText>

					<h:outputLabel value="Telefone 2" for="telefone2"/>
					<p:inputText id="telefone2" value="#{adminBean.administrador.pessoa.telefone2}"
						size="10" maxlength="10" required="false">
					</p:inputText>

					<h:outputLabel value="Email *" for="email"/>
					<p:inputText id="email" value="#{adminBean.administrador.pessoa.email}"
						maxlength="100" size="100"
						required="true" requiredMessage="Informe o email"
						validatorMessage="Informe um email válido">
						<f:validateRegex pattern="[a-zA-Z0-9\-\_\.]+@[a-zA-Z0-9\-\_\.]+"/>
					</p:inputText>							
										  
				</h:panelGrid>
				
				<p:commandButton action="#{adminBean.salvar}" value="Salvar" ajax="false" icon="ui-icon-check" style="margin:0"/>
								 
			</h:form>
			
		</p:panel>
	</ui:define>
</ui:composition>

</html>

Bem, tecnicamente, você está passando um valor nulo no campo cidade, porém, o que deve acontecer é que não está passando uma mensagem para detalhar melhor.
Caso realmente não esteja passando o valor para ser uma expressão suficiente para que o usuário entenda o que está acontecendo, ou seja porquê o erro aconteceu.
Para facilitar, coloque o atributo requiredMessage=“COLOQUE A MENSAGEM QUE VAI APARECER QUANDO O USUÁRIO PERSISTIR NO ERRO”. também pode olhar na apostila da AlgaWors e estudar sobre um tipo de utilitário de mensagens, e forçar uma mensagem à partir de um arquivo, e então usá-la com uma declaração no FacesConfig.
se ainda tiver dúvidas, meu e-mail é smnjr@hotmail.com.
Confira também se não está errando ao passar o valor na própria página, algo como um value errado, caso não estiver recebendo, terá a mensagem padrão do Faces, baseando o endereço do país, no seu caso, português, tendo em vista a sua localidade e versão do JSF incorporado no projeto.
Espero ter sido util.

O meu selectOneMenu de cidade está definido com required=“true” e requiredMessage=“Selecione uma cidade” e essa validação esatá sendo feita corretamente.
O problema acontece quando eu clico no botão pra gravar, antes da execução do método salvar do meu ManagedBean e após a validação dos valores da tela.
Acredito que tenha algo errado com o meu CidadeConverter, mas não identifiquei o que é. Vou cotinuar buscando a solução…qualquer coisa eu posto aqui.

Bem, o problema acontece por causa da anotação @RequestScoped. Pelo que entendi, toda vez que eu altero o estado ele cria um novo AdministradorBean para preencher as cidades do estado e assim que eu pressionar o botão salvar, ele vai criar outro e aí acontece o problema.
Mudei meu Bean para @ViewScoped e estou testando, só que estou recebendo uma nova mensagem de erro: “could not resolve property: pessoa.documento of: sistemasas.administrador.Administrador”
Alguém sabe porque esse erro acontece?

Galera, consegui resolver tudo…
O erro do post acima era coisa do hibernate. Em uma das minhas consultas eu verificava se existia um Administrador cadastrado com o documento informado. O método no DAO tava errado.
Estava assim:

    @Override
    public boolean documentoCadastrado(Administrador administrador) {

	Criteria criteria = sessao.createCriteria(this.classePersistente);
	criteria.add(Restrictions.eq("pessoa.documento", administrador.getPessoa().getDocumento()));
	criteria.add(Restrictions.ne("pessoa.id", administrador.getPessoa().getId()));
			
	return (! criteria.list().isEmpty());
	
    }

consegui resolver criando um alias para o objeto pessoa associado e ficou assim:

    @Override
    public boolean documentoCadastrado(Administrador administrador) {

	Criteria criteria = sessao.createCriteria(this.classePersistente);
	criteria.createAlias("pessoa", "pessoa");
	criteria.add(Restrictions.eq("pessoa.documento", administrador.getPessoa().getDocumento()));
	criteria.add(Restrictions.ne("pessoa.id", administrador.getPessoa().getId()));
			
	return (! criteria.list().isEmpty());
	
    }

Já o problema inicial eu resolvi mudando a anotação @RequestScoped do meu AdministradorBean para @ViewScoped

qualquer dúvida entrem em contato

Bão tamém.
Fico feliz de tentar ajudar, parabéns, da próxima saberá a solução.