[RESOLVIDO] Problemas de validação: jsf2 + primefaces + hibernate

Bom dia pessoal.

Ao salvar o cadastro de clientes, estou recebendo a seguinte mensagem do faces message:

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

meu xhtml:

            <h:form id="formInclui"> 
                <div align="center">
                <h:outputText style="color:red" value="* campo obrigatorio"/>
                <br/>
                    <h:panelGrid id="panel" columns="3" cellpadding="5">  

                        <h:outputLabel style="font-size: small" for="nome" value="nome:" />  
                        <p:inputText required="true" style="font-size: small" value="#{clientesBean.cliente.nome}"   
                                id="nome" label="nome" />
                        <h:outputText value="*" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="tipo" value="F/J:" />  
                        <p:selectOneMenu required="true" style="font-size: small" value="#{clientesBean.cliente.acsTipoPessoa}" 
                                         id="tipo" label="tipo" converter="tipoPessoaConversor">
                            <f:selectItem itemValue="" itemLabel="--Selecione--"/>
                            <f:selectItems value="#{clientesBean.tipoPessoa}" var="tipo" itemLabel="#{tipo.descricao}" itemValue="#{tipo}"/>
                        </p:selectOneMenu>
                        <h:outputText value="*" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="documento" value="CPF/CNPJ:" />  
                        <p:inputText style="font-size: small" value="#{clientesBean.cliente.cpfCnpj}"   
                                id="documento" label="documento" />
                        <h:outputText value="" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="endereco" value="endereco:" />  
                        <p:inputText style="font-size: small" value="#{clientesBean.cliente.endereco}"   
                                id="endereco" label="endereco" />
                        <h:outputText value="" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="numero" value="numero:" />  
                        <p:inputText style="font-size: small" value="#{clientesBean.cliente.numero}"   
                                id="numero" label="numero" />
                        <h:outputText value="" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="complemento" value="complemento:" />  
                        <p:inputText style="font-size: small" value="#{clientesBean.cliente.complemento}"   
                                id="complemento" label="complemento" />
                        <h:outputText value="" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="bairro" value="bairro:" />  
                        <p:inputText style="font-size: small" value="#{clientesBean.cliente.bairro}"   
                                id="bairro" label="bairro" />
                        <h:outputText value="" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="estado" value="UF:" />  
                        <p:selectOneMenu required="true" style="font-size: small" value="#{clientesBean.cliente.acsEstado}" 
                                         id="estado" label="estado" converter="estadoConversor">
                            <p:ajax update="cidade" process="@this"  listener="#{clientesBean.atualizaCidades}"/>  
                            <f:selectItem itemValue="#{clientesBean.empresa.acsEstado}" itemLabel="#{clientesBean.empresa.acsEstado.uf}"/>
                            <f:selectItems value="#{clientesBean.estados}" var="estado" itemLabel="#{estado.uf}" itemValue="#{estado}"/>
                        </p:selectOneMenu>
                        <h:outputText value="*" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="cidade" value="cidade:" />  
                        <p:selectOneMenu required="false" style="font-size: small" value="#{clientesBean.cliente.acsCidade}" 
                                         id="cidade" label="cidade" converter="cidadeConversor" validator="comboValidador">
                            <f:selectItem itemValue="#{clientesBean.empresa.acsCidade}" itemLabel="#{clientesBean.empresa.acsCidade.cidade}"/>
                            <f:selectItems value="#{clientesBean.cidades}" var="cidade" itemLabel="#{cidade.cidade}" itemValue="#{cidade}"/>
                        </p:selectOneMenu>
                        <h:outputText value="*" style="color:red"/>

                        <h:outputLabel style="font-size: small" for="ddd" value="ddd" />
                        <p:inputText style="font-size:small; size:9px " value="#{clientesBean.cliente.ddd}"   
                                id="ddd" label="ddd" />  
                        <h:outputText value="" style="text-decoration-color:red"/>

                        <h:outputLabel style="font-size: small" for="telefone" value="Telefone:" />
                        <p:inputText style="font-size:small; size:9px " value="#{clientesBean.cliente.telefone}"   
                                id="telefone" label="telefone" />  
                        <h:outputText value="" style="text-decoration-color:red"/>

                        <h:outputLabel style="font-size: small" for="observacao" value="observacao:" />
                        <p:inputTextarea style="font-size: small" value="#{clientesBean.cliente.observacao}"   
                                id="observacao" label="observacao" />  
                        <h:outputText value="" style="text-decoration-color:red"/>

                    </h:panelGrid>
                    <h:panelGrid columns="2">
                        <p:commandButton action="#{clientesBean.inclui}" id="submitButton" icon="ui-icon-disk" 
                                         value="gravar" ajax="true" process="@all" 
                                         update=":formCliente" oncomplete="dlg1.hide();">
                        </p:commandButton>
                        <p:commandButton id="cancelButton" icon="ui-icon-close" value="cancelar" ajax="true" oncomplete="dlg1.hide();">
                        </p:commandButton>
                    </h:panelGrid>
                </div>
            </h:form> 

Minha classe de persistencia Cidade

@Entity
@Table(name="acs_cidade"
    ,catalog="jvmsoftware_db"
)
public class AcsCidade  implements java.io.Serializable {

     private int idCidade;
     private AcsEstado acsEstado;
     private String cidade;
     private Set<DlvEntregadores> dlvEntregadoreses = new HashSet<DlvEntregadores>(0);
     private Set<AcsEmpresa> acsEmpresas = new HashSet<AcsEmpresa>(0);
     private Set<DlvClientes> dlvClienteses = new HashSet<DlvClientes>(0);

    public AcsCidade() {
    }

    public AcsCidade(int idCidade, AcsEstado acsEstado, String cidade) {
        this.idCidade = idCidade;
        this.acsEstado = acsEstado;
        this.cidade = cidade;
    }
    public AcsCidade(int idCidade, AcsEstado acsEstado, String cidade, Set<DlvEntregadores> dlvEntregadoreses, Set<AcsEmpresa> acsEmpresas, Set<DlvClientes> dlvClienteses) {
       this.idCidade = idCidade;
       this.acsEstado = acsEstado;
       this.cidade = cidade;
       this.dlvEntregadoreses = dlvEntregadoreses;
       this.acsEmpresas = acsEmpresas;
       this.dlvClienteses = dlvClienteses;
    }
   
     @Id 
    @Column(name="id_cidade", unique=true, nullable=false)
    public int getIdCidade() {
        return this.idCidade;
    }
    
    public void setIdCidade(int idCidade) {
        this.idCidade = idCidade;
    }
@ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="estado", nullable=false)
    public AcsEstado getAcsEstado() {
        return this.acsEstado;
    }
    
    public void setAcsEstado(AcsEstado acsEstado) {
        this.acsEstado = acsEstado;
    }
    
    @Column(name="cidade", nullable=false, length=100)
    public String getCidade() {
        return this.cidade;
    }
    
    public void setCidade(String cidade) {
        this.cidade = cidade;
    }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="acsCidade")
    public Set<DlvEntregadores> getDlvEntregadoreses() {
        return this.dlvEntregadoreses;
    }
    
    public void setDlvEntregadoreses(Set<DlvEntregadores> dlvEntregadoreses) {
        this.dlvEntregadoreses = dlvEntregadoreses;
    }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="acsCidade")
    public Set<AcsEmpresa> getAcsEmpresas() {
        return this.acsEmpresas;
    }
    
    public void setAcsEmpresas(Set<AcsEmpresa> acsEmpresas) {
        this.acsEmpresas = acsEmpresas;
    }
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="acsCidade")
    public Set<DlvClientes> getDlvClienteses() {
        return this.dlvClienteses;
    }
    
    public void setDlvClienteses(Set<DlvClientes> dlvClienteses) {
        this.dlvClienteses = dlvClienteses;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 67 * hash + this.idCidade;
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final AcsCidade other = (AcsCidade) obj;
        if (this.idCidade != other.idCidade) {
            return false;
        }
        return true;
    }

    @Override  
    public String toString() {    
            return (idCidade + ":");  
    }  
}

meu conversor para Cidades:


@FacesConverter(value="cidadeConversor", forClass=AcsCidade.class)  
public class AcsCidadeConversor implements Converter{

    private static final long serialVersionUID = 1L;
    public SessionFactory sf = getSessionFactory();
    public Session session = sf.openSession();

    @Override  
    public Object getAsObject(FacesContext context, UIComponent component, String value) throws ConverterException {
        System.out.println("AcsCidadeConversor.getAsObject - value: " + value);
        Integer idCid; 
        if (value == null || "".equals(value) || "--Selecione--".equals(value)) {
            return null;
        }
        
        // pega o parametro do valor recebido
        String[] tokens = value.split(":");
        String param = tokens[0];
        // transforma o string do parametro em inteiro
        idCid = Integer.parseInt(param);
        
        if(param != null) {  
            return session.get(AcsCidade.class, idCid);  
        }  
        return null;  
    }  
  
    @Override  
    public String getAsString(FacesContext context, UIComponent component, Object object) throws ConverterException {  
        if(object != null && object instanceof AcsCidade) {  
            return ((AcsCidade)object).toString();  
        }  
        return null;  
    }  
}

Criei inclusive um validador para os combos, para ver se funcionava, mas a mensagem permanece e o registro não é salvo no banco. pelo validador criado por mim, passa.

@FacesValidator("comboValidador")
public class ComboValidador implements javax.faces.validator.Validator {

    public void validate(FacesContext fc, UIComponent uic, Object o) {
        String[] tokens = o.toString().split(":");
        String param = tokens[0];
        long parsedId;
            System.out.println("ComboValidador: " + param);

        try {
            System.out.println("ComboValidador: " + param);
            parsedId = Long.valueOf(param);
        } catch (NumberFormatException nfe) {
            throw new ValidatorException(new FacesMessage("Error parsing Id."));
        }

        if(parsedId == -1) {
            o = null;
            return;
        }
    }
}

Alguém tem idéia de como solucionar o problema?
PS: estou utilizando o mesmo combo para cadastro de entregadores, e funciona perfeitamente

Pessoal, retomando esta questão.

consegui resolver o problema de validação para a cidade, mas não sei como foi resolvido, pq o código está igual ao postado aqui anteriormente. Mas exclui e regerei equals e hashcode, refiz conversores, etc.

Notei que a cidade que dava erro de validação no aplicativo, era somente campinas, não sei se por coincidencia, mas a esta cidade já estava setada para usuario e empresa. Todas as outras cidades, não apresentava nenhum erro de validação.

Continuando…
Estou construindo outro aplicativo, e no cadastro de empresas, tenhos a mesma estrutura xhtml aprentada anteriormente, mas neste caso já tenho erro no validador do estado e da cidade.

Notei que desta vez, o estado SP e a cidade campinas, apresentam problemas de validação. E novamente tenhos o estado e a cidade já setados para usuario anteriormente.

Meus escopos dos beans estão como session.

Alguém saberia dizer se isso tem alguma relação?

criei parametros do tipo int para receber o id da lista dos combos, assim, não preciso mais dos conversores.

não é uma solução bonita, mas funcionou.

valeu.