Chave Composta Hibernate - Popular SelectOneMenu com Object utilizando Converter

Bom Dia Companheiros …

Estou com problema para entender a lógica aplicada para um selectOneMenu.

Introdução:
selectOneMenu é componente do Primefaces 3.5;
O selectOneMenu é carregado com objetos;
As classes envolvidas no selectOneMenu receberam subscrita de métodos (equals e hashCode)
A pesquisa que popula o objeto do selectOneMenu é realizada a partir de um relaciomento com chave composta (Objeto Projeto e Portifolio);

Sistema:
Hibernate 3.0.1
Glassfish 3.1.2
Primefaces 3.5

Testes com Sucesso!
Quando populo o selectOneMenu com o portifolioDao.consultar() , carregam os dados e o converter funciona adequadamente …

Teste com Erro!
Quando populo o selectOneMenu a partir da chave composta (Veja o callPortifolioCentroCustoByProjeto) carregam os dados mas o método equals do PortifolioModel sempre retorna false;
Testes: Tentei colocar no converter o dao de relacionamento mapeando todo objeto projetoPortifolioDao.getIdProjetoPortifolio().getPortifolio().getIdPortifolio para getAsString e portifolioDao.getById(new Long(value)) para getAsObject porém sem sucesso …

Abaixo códigos:

<h:panelGrid columns="2"> <h:outputText value="Projeto:" /> <p:selectOneMenu id="checkBoxProjeto" value="#{ordemServicoBean.os.projeto}" label="Projeto" filter="true" style="margin-left: 10px;width: 300px;height: 22px" filterMatchMode="startsWith" panelStyle="width:315px;" converter="converterProjetoSelectItem" required="true" > <f:selectItem itemLabel="Selecione Projeto" itemValue="" /> <f:selectItems value="#{ordemServicoBean.listaProjetos}" var="projeto" itemValue="#{projeto}" itemLabel="#{projeto.nome}"/> <p:ajax process="@this" listener="#{ordemServicoBean.callPortifolioCentroCustoByProjeto}" update="checkBoxPortifolio,checkBoxCentroCusto"/> </p:selectOneMenu> <p:separator/> <p:separator/> <h:outputText value="Item de Contrato (Portifolio):" /> <p:selectOneMenu id="checkBoxPortifolio" value="#{ordemServicoBean.os.portifolio}" label="Portifolio" filter="true" style="margin-left: 10px;width: 300px;height: 22px" filterMatchMode="startsWith" panelStyle="width:315px;" converter="converterPortifolioSelectItem" required="true" > <f:selectItem itemLabel="Selecione item de Contrato" itemValue="" /> <f:selectItems value="#{ordemServicoBean.listaPortifolios}" var="portifolio" itemValue="#{portifolio}" itemLabel="#{portifolio.nome}"/> </p:selectOneMenu> <p:separator/> <p:separator/> <h:outputText value="Centro de Custo:" /> <p:selectOneMenu id="checkBoxCentroCusto" value="#{ordemServicoBean.os.centroCusto}" label="Centro Custo" filter="true" style="margin-left: 10px;width: 300px;height: 22px" filterMatchMode="startsWith" panelStyle="width:315px;" converter="converterCentroCustoSelectItem" required="true" > <f:selectItem itemLabel="Selecione Centro de Custo" itemValue="" /> <f:selectItems value="#{ordemServicoBean.listaCentrosCusto}" var="centroCusto" itemValue="#{centroCusto}" itemLabel="#{centroCusto.nome}"/> </p:selectOneMenu> <p:separator/> <p:separator/> <h:outputText value="Area:" /> <p:selectOneMenu id="checkBoxTipoOS" value="#{ordemServicoBean.os.tipo}" label="Tipo de OS" filter="true" style="margin-left: 10px;width: 300px;height: 22px" filterMatchMode="startsWith" panelStyle="width:315px;" converter="converterTipoOSSelectItem" required="true" > <f:selectItem itemLabel="Selecione Tipo de OS" itemValue="" /> <f:selectItems value="#{ordemServicoBean.listaTipoOrdensServico}" var="tipoOS" itemValue="#{tipoOS}" itemLabel="#{tipoOS.nome}"/> <p:ajax process="@this" listener="#{ordemServicoBean.callStatusByTipoOS}" update="checkBoxStatus"/> </p:selectOneMenu> <p:separator/> <p:separator/> <h:outputText value="Status:" /> <p:selectOneMenu id="checkBoxStatus" value="#{ordemServicoBean.os.status}" label="Status" filter="true" style="margin-left: 10px;width: 300px;height: 22px" filterMatchMode="startsWith" panelStyle="width:315px;" converter="converterStatusSelectItem" required="true" > <f:selectItem itemLabel="Selecione o Status" itemValue="" /> <f:selectItems value="#{ordemServicoBean.listaStatus}" var="status" itemValue="#{status}" itemLabel="#{status.nome}"/> <p:ajax process="@this"/> </p:selectOneMenu> <p:separator/> <p:separator/> <h:outputText value="Codigo Outros:" /> <p:inputText label="Codigo Outros" value="#{ordemServicoBean.os.codigoOutros}" style="margin-left: 10px" required="true"/> <p:separator/> <p:separator/> <h:outputText value="Observacao: " /> <p:inputTextarea rows="10" cols="40" value="#{ordemServicoBean.os.observacao}" style="margin-left: 10px" /> </h:panelGrid>

Método Bean (ViewScoped)

[code]//Comando para popular Portifolio e Centro de Custo a partir do Projeto
public void callPortifolioCentroCustoByProjeto(){
//Captura Portifolio e Centro de Custo
listaProjetosPortifolio.clear();
// listaProjetosPortifolio = projetoPortifolioDao.consultarByProjeto(os.getProjeto());
//
// //Carrega somente Portifolios
// listaPortifolios.clear();
// for(ProjetoPortifolio pp: listaProjetosPortifolio){
// listaPortifolios.add(pp.getIdProjetoPortifolio().getPortifolio());
// }
//

    listaPortifolios = portifolioDao.consultar();
    //Carrega Centros de Custos
    listaCentrosCusto.clear();
    listaCentrosCusto = centroCustoDao.consultarByProjeto(os.getProjeto());

}[/code]

Converter

[code]@FacesConverter(value=“converterPortifolioSelectItem”)
public class ConverterPortifolioSelectItem implements Converter {
private PortifolioDao portifolioDao = new PortifolioDaoImpl();

@Override 
public Object getAsObject(FacesContext context, UIComponent component, String value) {
    System.out.println("getAsObject");
    if (value != null && !value.isEmpty()) {
        System.out.println("Object PortifolioModel");
        //seu método de pesquisa para trazer uma instância de Projeto
        return portifolioDao.getById(new Long(value));
    }

    return null;    
}  
@Override public String getAsString(FacesContext context, UIComponent component, Object object) {
    System.out.println("getAsString");
    if(object!=null && object instanceof PortifolioModel){
        System.out.println("Fez PortifolioModel");
        PortifolioModel portifolioModel = (PortifolioModel) object;  
        return  String.valueOf(portifolioModel.getIdPortifolio());
    }else{
        System.out.println("Nada PortifolioModel");
        return ""; 
    }
      
}

} [/code]

Models envolvidos

[code]@Entity
@Table(name=“tbl_portifolio”)
public class PortifolioModel implements Serializable {

@OneToMany(cascade={CascadeType.ALL},mappedBy="portifolio")
private Collection<OrdemServicoModel> listOSs;

@Id//Variável de ID no Banco de Dados
@Column(name="id_portifolio") 
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long idPortifolio;

@Column(name="nome",length=100,nullable=false)
private String nome;

@Column(name="descricao",length=100)
private String descricao;

@Temporal(javax.persistence.TemporalType.TIMESTAMP)
@Column(name="data_cadastro",nullable=false)
private Date dataCadastro;

@Column(name="usuario_cadastro",length=20,nullable=false)
private String usuarioCadastro;

//gettters and setters omitidos

@Override
public int hashCode() {
    int hash = 5;
    hash = 37 * hash + (int) (this.idPortifolio ^ (this.idPortifolio >>> 32));
    return hash;
}

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

}[/code]

[code]@Entity
@Table(name=“tbl_projeto”)
public class ProjetoModel implements Serializable {

@OneToMany(cascade={CascadeType.ALL},mappedBy="projeto")
private Collection<OrdemServicoModel> listOSs;

@OneToMany(cascade={CascadeType.ALL},mappedBy="projeto")
private Collection<CentroCustoModel> listCentrosCusto;


@Id//Variável de ID no Banco de Dados
@Column(name="id_projeto") 
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long idProjeto;

@Column(name="proprio",nullable=false)
private boolean proprio;

@Column(name="nome",length=100,nullable=false)
private String nome;

@Column(name="descricao",length=100)
private String descricao;

@Column(name="orcamento",nullable=false)
private double orcamento;

@Column(name="valor_total",nullable=false)
private double valorTotal;

@Column(name="observacao",length=100)
private String observacao;

@Column(name="usuario_cadastro",length=20,nullable=false)
private String usuarioCadastro;

@Temporal(javax.persistence.TemporalType.TIMESTAMP)
@Column(name="data_cadastro",nullable=false)
private Date dataCadastro;

//gettters and setters omitidos

@Override
public int hashCode() {
    int hash = 7;
    hash = 61 * hash + (this.nome != null ? this.nome.hashCode() : 0);
    return hash;
}

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

}[/code]

[code]@Embeddable
public class ProjetoPortifolioId implements Serializable{

@ManyToOne(fetch = FetchType.LAZY,optional=false)
private ProjetoModel projeto;


@ManyToOne(fetch = FetchType.LAZY,optional=false)
private PortifolioModel portifolio;

/**
 * @return the projeto
 */
public ProjetoModel getProjeto() {
    return projeto;
}

/**
 * @param projeto the projeto to set
 */
public void setProjeto(ProjetoModel projeto) {
    this.projeto = projeto;
}

/**
 * @return the portifolio
 */
public PortifolioModel getPortifolio() {
    return portifolio;
}

/**
 * @param portifolio the portifolio to set
 */
public void setPortifolio(PortifolioModel portifolio) {
    this.portifolio = portifolio;
}

@Override
public int hashCode() {
    int hash = 5;
    hash = 59 * hash + (this.projeto != null ? this.projeto.hashCode() : 0);
    hash = 59 * hash + (this.portifolio != null ? this.portifolio.hashCode() : 0);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final ProjetoPortifolioId other = (ProjetoPortifolioId) obj;
    if (this.projeto != other.projeto && (this.projeto == null || !this.projeto.equals(other.projeto))) {
        return false;
    }
    if (this.portifolio != other.portifolio && (this.portifolio == null || !this.portifolio.equals(other.portifolio))) {
        return false;
    }
    return true;
}[/code]

[code]@Entity
@Table(name=“rel_projeto_portifolio”)
public class ProjetoPortifolio implements Serializable{

@EmbeddedId
private ProjetoPortifolioId idProjetoPortifolio;

@Temporal(javax.persistence.TemporalType.TIMESTAMP)
@Column(name="data_cadastro",nullable=false)
private Date dataCadastro;

@Column(name="usuario_cadastro",length=20,nullable=false)
private String usuarioCadastro;


/**
 * @return the dataCadastro
 */
public Date getDataCadastro() {
    return dataCadastro;
}

/**
 * @param dataCadastro the dataCadastro to set
 */
public void setDataCadastro(Date dataCadastro) {
    this.dataCadastro = dataCadastro;
}

/**
 * @return the usuarioCadastro
 */
public String getUsuarioCadastro() {
    return usuarioCadastro;
}

/**
 * @param usuarioCadastro the usuarioCadastro to set
 */
public void setUsuarioCadastro(String usuarioCadastro) {
    this.usuarioCadastro = usuarioCadastro;
}

/**
 * @return the idProjetoPortifolio
 */
public ProjetoPortifolioId getIdProjetoPortifolio() {
    return idProjetoPortifolio;
}

/**
 * @param idProjetoPortifolio the idProjetoPortifolio to set
 */
public void setIdProjetoPortifolio(ProjetoPortifolioId idProjetoPortifolio) {
    this.idProjetoPortifolio = idProjetoPortifolio;
}

}
[/code]
Esse é o único selectOneMenu que não quer funcionar, não possui caractere especial (somente espaços entre nomes compostos);

Desde já agradeço pela atenção!

Bom Dia

O problema foi resolvido invertendo um pouco maneira de pensar, em vez de acessar o objeto que continha as chaves dos dois objetos (Portifolio e Projeto), acessei pelo objeto e fiz um inner join através de HQL.

No problema citado nas mensagens acima, não consigo ver o erro, pois se o relacionamento possui dois objetos poderia realizar restrições na criteria e popular no bean tratando somente os objetos no qual necessitaria.

A única explicação que vejo é que o objeto (Projeto e Portifolio) vindo da classe “ProjetoPortifolio” possui um hashcode diferente que se avaliado individualmente para as classes Projeto e Portifolio geram tal erro.

Solução:

Método Bean

[code]//Comando para popular Portifolio e Centro de Custo a partir do Projeto
public void callPortifolioCentroCustoByProjeto(){
//Captura Portifolio e Centro de Custo
listaProjetosPortifolio.clear();
listaPortifolios.clear();
listaPortifolios = portifolioDao.consultarByProjeto(os.getProjeto());
//Carrega Centros de Custos
listaCentrosCusto.clear();
listaCentrosCusto = centroCustoDao.consultarByProjeto(os.getProjeto());

}[/code]

DaoImpl

[code]@Override
public List consultarByProjeto(ProjetoModel projeto) {
try{
HibernateUtility.beginTransaction();

        String hql = "select p from PortifolioModel p, ProjetoPortifolio pp " +
                "where p.idPortifolio = pp.idProjetoPortifolio.portifolio.idPortifolio and  " + 
                "pp.idProjetoPortifolio.projeto.idProjeto = :id";
        Query query = HibernateUtility.getSession().createQuery(hql);
        query.setLong("id", projeto.getIdProjeto());
        lista = (List) query.list();
        HibernateUtility.closeSession();
        return lista;
   }catch (HibernateException hibernateException){
        cancel();
        throw hibernateException;            
    }
}[/code]

O converter é o mesmo citado anteriormente …

Caso alguém consiga explicar ocorrido a informação será bem vinda.

Agradeço a todos que leram o post.