JSF 2.0 - Como pegar objeto inteiro no selectOneMenu

Boa tarde pessoal,

Estou com um problema para pegar objetos selecionados no combo, estive pesquisando e ouvi falar sobre converters e em alguns casos vi que ele nao é necessário.

Eu fiz da seguinte maneira. Criei um atributo no MB que receberia esse objeto selecionado, mas por alguma razao ele nao está setando o atributo.

Abaixo segue meu código para ajudar.

Bean

@ManagedBean(name = "nivelOrganizacionalController")
@ViewScoped
public class NivelOrganizacionalController {
    
    PreTarefaEntity preTarefa;

    public void associarPreTarefa(){
        PreTarefaNivelOrganizacionalEntity preTarefaNO = new PreTarefaNivelOrganizacionalEntity();
        preTarefaNO.setPreTarefa(preTarefa);
        preTarefaNO.setNivelOrganizacional(nivelOrganizacional);
        nivelOrganizacionalDAO.salvar(preTarefaNO);
     }

     public PreTarefaEntity getPreTarefa() {
        return preTarefa;
    }

    public void setPreTarefa(PreTarefaEntity preTarefa) {
        this.preTarefa = preTarefa;
    }

***O atributo preTarefa é o que deveria receber o objeto do combo.

XHTML

          <h:selectOneMenu value="#{nivelOrganizacionalController.preTarefa}">
              <f:selectItem itemLabel="Selecione" itemValue="" noSelectionOption="true" />
             <f:selectItems value="#{preTarefaController.comboPreTarefa}" var="preTarefa" itemLabel="#{preTarefa.nome}" itemValue="#{preTarefa.idPreTarefa}"/>
         </h:selectOneMenu> 

Se puderem me ajudar ficarei extremamente agradecido! Abraços!

cara,

vc tem que criar um custom converter.

t+

No JSF 2 da para pegar direto sem converter mas não sei aonde eu vi…De uma procurada.

Eu tinha visto que dava, só que até hoje não achei onde.
Use converter

Estou lendo aqui a respeito, já implementei um exemplo sem converter, mas ano funcionou, vou tentar com converter mesmo! Muito obrigado a todos!

.

Esta ai sem conversor:

<h:SelectOneMenu disabled="#{caminhaoBean.aplicacao.podeAlterar}" value="#{caminhaoBean.caminhao.cliente}" id="listaCliente" style="width:350px"> <f electItem itemLabel="Selecione" itemValue="" /> <f electItems value="#{clienteBean.colecao}" var="x" itemLabel="#{x.nomeFantasia}" itemValue="#{x}" /> <f:ajax render="listaCliente" execute="@this" /> </h electOneMenu>

[quote=FernandoFranzini]Esta ai sem conversor:

<h:SelectOneMenu disabled="#{caminhaoBean.aplicacao.podeAlterar}" value="#{caminhaoBean.caminhao.cliente}" id="listaCliente" style="width:350px"> <f electItem itemLabel="Selecione" itemValue="" /> <f electItems value="#{clienteBean.colecao}" var="x" itemLabel="#{x.nomeFantasia}" itemValue="#{x}" /> <f:ajax render="listaCliente" execute="@this" /> </h electOneMenu>[/quote]

Ja fiz assim e não funcionou pelo menos comigo tanto que ao usar o converter fica igual o codigo nao muda apenas adiciona o converter

Já passei pelo mesmo problema ha algum tempo atrás e posto aqui a minha solução para JSF 2 usando prime faces. Tenho tb uma solução para JSF 1 usando richfaces, quem tiver interesse postar aqui que eu mando.

JSF 2.0 COM PRIME FACES.

[color=red]ANTES DE COMEÇAR É NECESSÁRIO DIZER QUE PARA A SOLUÇÃO ABAIXO FUNCIONAR VOCÊ TEM QUE NA CLASSES DE SUAS ENTIDADES VOCÊ SOBRESCREVER EXPLICITAMENTE OS MÉTODOS equals E hashcode. Para o exemplo abaixo funcionar a classe Cliente teria que sobrescrever o método equals e hashcode. Como você não vai ta fazendo isso em todas as suas classes de entidade, então basta criar uma superclasse abstrata de entidade e sobrescrever esses métodos lá e todas as entidades estendenrão desta. Por exemplo uma classe chamada Entidade que é abstrata.[/color]

[color=red]OUTRA COISA IMPORTANTE É QUE DA FORMA COMO O CONVERTER ESTA IMPLEMENTADO ABAIXO ELE ESPERA QUE O ITEM TENHA UM ATRIBUTO CHAMADO ‘id’ QUE É O IDENTIFICADOR NORMALMENTE USADO PARA ENTIDADES. CASO NO SEU PROJETO TENHA OUTRO PADRÃO FIQUE A VONTADE PARA MUDAR A PROPRIEDADE NO MÉTODO getIdByReflection DO CONVERTER.[/color]

Para tal é necessário colocar o converter abaixo:

import java.lang.reflect.Field;
import java.util.Collection;

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;

/**
 * 
 * @author Victor Lindberg
 *
 */
@FacesConverter("selectOneUsingObjectConverter")
public class SelectOneUsingObjectConverter implements Converter{
	
	@Override
    public Object getAsObject(FacesContext context,
        UIComponent component, String value) {
        if (value == null || value.equals(""))
            return null;

        try{
        	Long id = Long.valueOf(value);
        	Collection items =  (Collection) component.getAttributes().get("items");
        	return findById(items, id);
        }catch(Exception ex){
        	throw new ConverterException("Não foi possível aplicar conversão de item com valor ["+value+"] no componente ["+component.getId()+"]", ex);
        }
    }
	
    @Override
	public String getAsString(FacesContext context, UIComponent component,
			Object value) {
		if (value == null)
			return "";
		
		return getIdByReflection(value).toString();
	}
    
    private Object findById(Collection collection, Long idToFind){
    	for (Object obj : collection){
    		 Long id = getIdByReflection(obj);
    		 if (id == idToFind)
    			 return obj;
    	}
    	
    	return null;
    }
    
    private Long getIdByReflection(Object bean){
    	try{
    		Field idField = bean.getClass().getDeclaredField("id");
    		idField.setAccessible(true);
    		return (Long) idField.get(bean);
    	}catch(Exception ex){
    		throw new RuntimeException("Não foi possível obter a propriedade 'id' do item",ex);
    	}
    }

}

Nosso MB:

[code]import java.util.List;

import javax.faces.bean.ManagedBean;

/**
*

  • @author Victor Lindberg

*/
@ManagedBean(“clienteMB”)
public class ClienteMB {

private List<Cliente> listaClientes;

private Cliente clienteSelecionado;

public List<Cliente> getListaClientes() {
	//carrega a lista de clientes
	return listaClientes;
}

public void setListaClientes(List<Cliente> listaClientes) {
	this.listaClientes = listaClientes;
}

public Cliente getClienteSelecionado() {
	return clienteSelecionado;
}

public void setClienteSelecionado(Cliente clienteSelecionado) {
	this.clienteSelecionado = clienteSelecionado;
}

}[/code]

Então para usar basta definir ele como sendo o converter e colocar explicitamente um atributo chamado ‘items’ na tag selectOneMenu como abaixo.

<p:selectOneMenu id="combo" value="#{clienteMB.clienteSelecionado}" converter="selectOneUsingObjectConverter" items="#{clienteMB.listaClientes}"> <f:selectItem itemLabel="Selecione" itemValue="" /> <f:selectItems value="#{clienteMB.listaClientes}" var="cliente" itemLabel="#{cliente.nome}" itemValue="#{cliente}" /> </p:selectOneMenu>

Pronto, nossa combo do JSF ta funcionando belezinha.

É isso ai, qualquer coisa posta ae.

Victor Lindberg

Excelente lindberg713

Descuple ressuscitar o post, mas assim como eu, outros podem precisar disto.

No meu caso, eu uso primefaces (é idêntico ao post do lindberg713):

<p:selectOneMenu style="width:45px;" converter="selectOneConverter" items="#{manterPessoasBean.ufs}"> <p:ajax event="change" listener="#{manterPessoasBean.setarUf}" update="@form" /> <f:selectItems value="#{manterPessoasBean.ufs}" var="uf" itemLabel="#{uf.sigla}" itemValue="#{uf}"/> </p:selectOneMenu>
Mas vejam que usei <p:ajax> com um listener. O listener ficou assim:

public void setarUf(javax.faces.event.AjaxBehaviorEvent event){ Map<String, Object> map = event.getComponent().getAttributes(); uf = (Uf) map.get("value"); }
… e é claro, sobrescrevendo os metodos equals e hashCode da classe de dominio - basta acrescentar o código abaixo (no meu caso Uf):

[code]public boolean equals(Object other){
return other instanceof Uf && equals((Uf)other);
}

public boolean equals (Uf other){
return this.id.equals(other.id);
}

public int hashCode(){
return id.hashCode();
}

public String toString(){
return this.nome;
}[/code]
Assim funciona melhor do que as outras abordagens mostradas neste post, pelo menos com primefaces.
Fui…

[quote=knik]Excelente lindberg713

Descuple ressuscitar o post, mas assim como eu, outros podem precisar disto.

No meu caso, eu uso primefaces (é idêntico ao post do lindberg713):

<p:selectOneMenu style="width:45px;" converter="selectOneConverter" items="#{manterPessoasBean.ufs}"> <p:ajax event="change" listener="#{manterPessoasBean.setarUf}" update="@form" /> <f:selectItems value="#{manterPessoasBean.ufs}" var="uf" itemLabel="#{uf.sigla}" itemValue="#{uf}"/> </p:selectOneMenu>
Mas vejam que usei <p:ajax> com um listener. O listener ficou assim:

public void setarUf(javax.faces.event.AjaxBehaviorEvent event){ Map<String, Object> map = event.getComponent().getAttributes(); uf = (Uf) map.get("value"); }
… e é claro, sobrescrevendo os metodos equals e hashCode da classe de dominio - basta acrescentar o código abaixo (no meu caso Uf):

[code]public boolean equals(Object other){
return other instanceof Uf && equals((Uf)other);
}

public boolean equals (Uf other){
return this.id.equals(other.id);
}

public int hashCode(){
return id.hashCode();
}

public String toString(){
return this.nome;
}[/code]
Assim funciona melhor do que as outras abordagens mostradas neste post, pelo menos com primefaces.
Fui…
[/quote]

Amigo, não considero essa sua abordagem melhor do que as outras. Veja que a ideia que passei aqui é que seja transparente, ou seja, você define seu selectOneMenu , define seus itens, define qual é o value dele (onde o valor selecionado será setado), e pronto só isso. O converter faz o resto para você sempre do mesmo jeito e para todos os casos, atributos e selectOneMenus que você tenha.

Usando a sua abordagem, você sempre terá que criar esse método listener para cada atributo e caso separadamente. Visto que você vai ter que obter o valor correto do map de atributos, fazer o cast e setar no local correto dentro do seu managedbean. Eu não acho essa abordagem uma boa escolha. E te digo mais, isso que você fez é redundante pois nesse trecho de código que vc postou do selectOneMenu usando o converter que eu postei anteriormente + o atributo items, quando o jsf invocar o seu metodo listener manterPessoasBean.setarUf o jsf já teria setado o valor selecionado na combo corretamente no atributo correspondente definido no value pois a chamada ao método do listener será feita na fase de 4 do jsf (Update Model Values) e depois disso só entao o seu listerner ou action será chamado na fase 5 (Invoke Application). Então você vai ta fazendo algo redundante e que ja ta sendo feito automaticamente e pra todos os casos bastando apenas usar o converter e o atributo extra ‘items’.

ooops foi mal lindberg713.

Você tem a inteira razão, eu me esqueci de dizer que estou usando duas combos. Entao precisa sim do listener, para setar a segunda combo com as cidades da uf selecionada, no mais você tem razao, usando apenas uma combo o listener é totalmente dispensável.

Parabéns pela sua idéia e obrigado.

Em casos como este onde se precisa efetuar uma ação em função de um item selecionado na combo, como por exemplo listar os estados em uma combo em função de um pais selecionado em outra combo, claro que é necessário um actionlistener ou um simples action. Mas uma coisa nao tem nada haver com a outra. A solução tratada aqui é para se obter setando na value da combo o item selecionado diretamente sem a necessidade de se criar converters especificos para isto.

Mas entendi o que você quis dizer. So quis deixar claro que o listener nao tem nada haver com a solução discutida aqui. Mas sempre é bom receber os feedbacks. Estamos todos aqui é pra isso mesmo, pra discutir e unir forças em prol de um senso comum.

Abraço.

Cara, vi isso no Blog do Rafael Pontes http://www.rponte.com.br/2008/07/26/entity-converters-pra-da-e-vender/
Eu encontrei agora e achei interessante, ainda não implementei mas é semelhante a solução já apresentada aqui, com mais um exemplo e considerações.
o que acham? é assim mesmo ou já tem outra forma, biblioteca, etc…

obg,

O lindberg713 , só faltou uma coisa a dizer, tem que mapear esse conveter num xml?

Opa. Se você estiver usando JSF 2, não precisa mapear nada. Observe que o converter está anotado com @FacesConverter. No JSF 2 não precisa pois ele já detecta e registra os converters (e validadores tb) anotados. Se estiver usando JSF 1, é necessário mapear no faces-config.xml.

Quanto ao exemplo que você passou no link http://www.rponte.com.br/2008/07/26/entity-converters-pra-da-e-vender/, não testei ainda mas pelo que vi é semelhante ao apresentado aqui sim. Só não sei se essa forma de pegar implicitamente o objeto selecionado a partir de component.getAttributes().get(value) funciona para todos os casos. A solução que postei aqui funciona sempre pois passamos a lista contendo os valores possiveis sempre, então independente do que aconteça, o valor selecionado será obtido corretamente. Ma a solução do post é a mesma apresentada aqui só que sem a necessidade do atributo ‘items’. Quem quiser testar em diversos casos e nos devolver um feedback, seja bem vindo.

Opa. Se você estiver usando JSF 2, não precisa mapear nada. Observe que o converter está anotado com @FacesConverter. No JSF 2 não precisa pois ele já detecta e registra os converters (e validadores tb) anotados. Se estiver usando JSF 1, é necessário mapear no faces-config.xml.

Quanto ao exemplo que você passou no link http://www.rponte.com.br/2008/07/26/entity-converters-pra-da-e-vender/, não testei ainda mas pelo que vi é semelhante ao apresentado aqui sim. Só não sei se essa forma de pegar implicitamente o objeto selecionado a partir de component.getAttributes().get(value) funciona para todos os casos. A solução que postei aqui funciona sempre pois passamos a lista contendo os valores possiveis sempre, então independente do que aconteça, o valor selecionado será obtido corretamente. Ma a solução do post é a mesma apresentada aqui só que sem a necessidade do atributo ‘items’. Quem quiser testar em diversos casos e nos devolver um feedback, seja bem vindo.[/quote]

Opa, de fato, JSF2+anotations “belo casal”. nem preciasa mesmo do xml.

Bom eu testei a segunda implementação citada pelo Rafael Pontes(SimpleEntityConverter), que recupera o objeto do selectItem através do seu “index”. A grande vantagem é que pode ser usado em qualquer “selectOneMenu” com qualuqer objeto sem ter que mudar teus “Entities(Beans)” a não ser o métodos “equals” e “hashCode”, o único problema/incoveniente que encontrei é que no o meu método, por exemplo, getCidades deve retornar um List e não um List, mas talvez seja apenas uma falta de atenção minha em mudar alguma coisa, o fato é que fiquei ontem o dia inteiro a procura dessa solução e só consegui fazer funcionar lá pelas 4 da madruga com essa idéia… ops, “ideia”.
Agora(13h00 em Rondônia) to no trampo, que não tem nada a ver com isso, e não tenho como postar código e tals, mas chegando em cada faço um resumo com o que consegui implementar e vcs sugiram, critiquem, comentem, etc…

deu “tiute” aqui e acabei editando, enviei duas vezes.

Opa. Se você estiver usando JSF 2, não precisa mapear nada. Observe que o converter está anotado com @FacesConverter. No JSF 2 não precisa pois ele já detecta e registra os converters (e validadores tb) anotados. Se estiver usando JSF 1, é necessário mapear no faces-config.xml.

Quanto ao exemplo que você passou no link http://www.rponte.com.br/2008/07/26/entity-converters-pra-da-e-vender/, não testei ainda mas pelo que vi é semelhante ao apresentado aqui sim. Só não sei se essa forma de pegar implicitamente o objeto selecionado a partir de component.getAttributes().get(value) funciona para todos os casos. A solução que postei aqui funciona sempre pois passamos a lista contendo os valores possiveis sempre, então independente do que aconteça, o valor selecionado será obtido corretamente. Ma a solução do post é a mesma apresentada aqui só que sem a necessidade do atributo ‘items’. Quem quiser testar em diversos casos e nos devolver um feedback, seja bem vindo.[/quote]

Opa, de fato, JSF2+anotations “belo casal”. nem preciasa mesmo do xml.

Bom eu testei a segunda implementação citada pelo Rafael Pontes(SimpleEntityConverter), que recupera o objeto do selectItem através do seu “index”. A grande vantagem é que pode ser usado em qualquer “selectOneMenu” com qualuqer objeto sem ter que mudar teus “Entities(Beans)” a não ser o métodos “equals” e “hashCode”, o único problema/incoveniente que encontrei é que no o meu método, por exemplo, getCidades deve retornar um List e não um List, mas talvez seja apenas uma falta de atenção minha em mudar alguma coisa, o fato é que fiquei ontem o dia inteiro a procura dessa solução e só consegui fazer funcionar lá pelas 4 da madruga com essa idéia… ops, “ideia”.
Agora(13h00 em Rondônia) to no trampo, que não tem nada a ver com isso, e não tenho como postar código e tals, mas chegando em cada faço um resumo com o que consegui implementar e vcs sugiram, critiquem, comentem, etc…[/quote]

Não analisei o código para verificar se de fato a lista de items tem que ser obrigatoriamente de SelectItem. Se for, essa solução para mim já passa a ser mesmo recomendada pelo fato de que vc sempre vai ter que criar uma lista e popula-la com selectitems toda vez em todos os atributos e para cada selectonemenu.

A solução que propus te deixa livre deste problema. Visto que ela pega uma coleção diretamente com os objetos. Então vc não precisa fazer nada disso, fica transparente pois pega diretamente o valor da collection de items do bean em questão.

É, também não analisei muito sobre o List, apenas resolvi meu problema de “usuario.cidade” receber um “objeto - Cidade - selecionado no selectOneMenu” mais tarde testo mais e posto comentários.

ps.: objeto Cidade entre aspas né.