Renato M Miyasaki

Como fazer, links de Gestão de TI e programação.

JSF + Facelets: alterar objeto agregado em um droplist

Estou fazendo uma prova de conceito com JSF + Facelets + Hibernate, e tive problemas em alterar um objeto agregado em um droplist.

Antes, eu estava somente colocando o código identificador do objeto que queria modificar, e assim ele me dava o erro “org.hibernate.HibernateException: identifier of an instance …

O código antes era:

<h:selectOneMenu id=”forn” value=”#{NotaFiscalBean.notaFiscal.fornecedor.codFornecedor}” >
<f:selectItems value=”#{NotaFiscalBean.fornecedores}” ></f:selectItems>
</h:selectOneMenu>

Onde #{Bean.notaFiscal.fornecedor.codFornecedor} é o código do objeto agregado e;
#{NotaFiscalBean.fornecedores} é uma lista de objetos do tipo Map (na verdade, SelectItem) com os valores possíveis. E a chave continha o código identificador e o valor, o nome do fornecedor.

O novo código passou a ser:

<h:selectOneMenu id=”forn” converter=”#{NotaFiscalBean.fornecedorConverter}
value=”#{NotaFiscalBean.notaFiscal.fornecedor}” >
<f:selectItems value=”#{NotaFiscalBean.fornecedores}” ></f:selectItems>
</h:selectOneMenu>

Onde: #{NotaFiscalBean.notaFiscal.fornecedor} é o objeto agregado;
#{NotaFiscalBean.fornecedores} é igual acima, exceto que na chave do mapeamento passei a utilizar os objetos;
#{NotaFiscalBean.fornecedorConverter} é uma classe que implementa a interface javax.faces.convert.Converter

Na implementação de javax.faces.convert.Converter, você precisa implementar os métodos:
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) e;
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2).

Adicionalmente, inclui o construtor que recebe a lista dos possíveis objetos.

Então, a minha classe Converter ficou assim:

package com.renatom.jsf.converter;

import java.util.List;

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

import com.renatom.jsf.model.Fornecedor;

public class FornecedorConverter implements Converter {

List <Fornecedor> list;

public FornecedorConverter(List<Fornecedor> fornecedores) {
list = fornecedores;
}

@Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) {
if (arg2 == null || arg2.length() == 0)
return null;

long id = Long.valueOf(arg2).longValue();
if (id < 0)
return null;

Fornecedor fornRet = null;
for (Fornecedor forn : list) {
if (forn.getCodFornecedor() == id) {
fornRet = forn;
break;
}
}
return fornRet;
}

@Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
if (arg2==null) return "-1";
Fornecedor forn = (Fornecedor)arg2;
return String.valueOf(forn.getCodFornecedor());
}
}

Fonte: http://seamframework.org/Community/SelectOneMenuAndJPAManyToOne