Solução para pegar valor SelectOneMenu sem utilizar converter - SIMPLES [RESOLVIDO]

8 respostas
F

Boa noite pessoal,

Estou aqui para contribuir/compatilhar com vocês uma solução que fiz para que se tenha o objeto no nosso menaged bean, sendo esse selecionado no SelectOneMenu, e isso sem a utilização de uma classe converter.
Eu procurei muito, revirei a internet e só encontrei problemas iguais ao meu. Encontrei “soluções” que acabavam por não resolver o problema, onde uma delas sugeria fazer a classe converter de um Managed Bean, onde não achei muito interessante, e que também não consegui fazer funcionar corretamente, dando muitos erros e me levando a loucura com tanto problema. No próprio fórum eu não consegui encontrar coisas claras e que realmente funcionassem.

Como sabemos, quando o SelectOneMenu carrega a lista de objetos, o que realmente está sendo mostrando não são eles, e sim strings, mais precisamente o caminho da classe e o id de cada objeto. Por consequência, quando selecionamos o valor que queremos, ao enviar para o servidor, claro, o que vai é a string, dai a necessidade de utilizar o converter, que pega o id do mesmo, converte para inteiro e faz a busca do objeto, com isso finalizando e retornando o mesmo.

O que acontece é que erros como: nullpointers com EJBs e outros objetos, são comuns. Tem a questão de utilizar lista de SelectItens ao invés das Classes que queremos, em fim, eu já estava ficando louco da cabeça de tentar resolver e não conseguir.
P.S: Estou utilizando JPA 2.1 e a injeção de EJBs nos converters creio eu que ainda não foi implementada nesse nova especificação, pois tentei de tudo e somente retorna nullpointers. Tentei lookup, de tudo, e simplesmente não funciona.

MInha solução:

Como eu disse, o que está sendo mostrado no SelectOneMenu são simplesmente strings que possuem o caminho da classe com os respectivos ids atrelados a cada string para representar cada objeto, tendo observado isso pensei: porque não setar a string no ManagedBean e tratar ela la ? … Achei bem mais simples !!!

Como ? … abaixo minha solução:

Aqui é o trecho da minha página xhtml contendo o SelectOneMenu:

<p:selectOneMenu   id="pivo" value="#{cadastroResultadoMB.pivoSelecionado}">
                            <f:selectItem  itemLabel="Selecione um pivo"/>
                            <f:selectItems var="pv" value="#{cadastroResultadoMB.pivo}"
                                           itemValue="#{pv}"
                                           itemLabel="#{pv.nome}" 
                                           />
</p:selectOneMenu>

Minha Lista de Pivos
P.S: pivoDAO é um EJB Stateless

public List<Pivo> getPivo() {
        this.listaPiv = pivoDAO.findAll();
        return listaPiv;
    }

Métodos Get e Set do tipo String, pois o valor será recebido como tal e não um objeto.

public String getPivoSelecionado() {
        return pivoSelecionado;
    }

    public void setPivoSelecionado(String pivoSelecionado) {
        this.pivoSelecionado = pivoSelecionado;
    }

Quando a string é setada, ela vem da seguinte forma: br.com.embrapa.moscabranca.Pivo[ idPivo=1 ] (esse é o caminho da minha classe com o id do respectivo objeto representado pela string que selecionei no SelectOneMenu)
Vem exatamente assim !
O que devemos fazer é utilizar o método raplaceAll e retirar a parte da string que representa o id do objeto, converter ele pra inteiro e pronto, agora é só fazer a busca do mesmo.

public void objeto(){
     
        String s = pivoSelecionado.replaceAll("[^[telefone removido]]", "");
        int id = Integer.parseInt(s);
        Pivo pivo = pivoDAO.find(id);
    }

Concordo que não seja a solução mais elegante, mas que é melhor do que tonar um converter um ManagedBean, isso é !!

Peço desculpas caso o que eu disse aqui já tenha sido proposto em algum outro tópico. Se isso já tiver ocorrido, desconsiderem, por favor.

Abraços a todos.

8 Respostas

D

Para que tudo isso? Se a classe Pivo possui um atributo que garanta sua unicidade, como um id, por exemplo, basta colocá-lo como itemValue e o resto você sabe, não?

F

Olá, bom dia !

Não, não funciona !
SelectOneMenu não possui o atributo itemValue, correto ! Quem possui esse atributo ai é o selectItem e selectItems. Quando eu seleciono um valor na combo, quem captura esse valor selecionado é o SelectOneMenu e com isso tenho o atributo Value para pegar esse retorno, e ai volta no que contei acima.
O que vc está dizendo é para eu fazer isso aqui neh:

<p:selectOneMenu   id="pivo" value="#{cadastroResultadoMB.pivoSelecionado}">  
                            <f:selectItem  itemLabel="Selecione um pivo"/>  
                            <f:selectItems var="pv" value="#{cadastroResultadoMB.pivo}"  
                                           itemValue="#{pv.idPivo}"  
                                           itemLabel="#{pv.nome}"   
                                           />  
</p:selectOneMenu>

colocar no itemValue o id correto ?

Pois então, de qualquer forma vai precisar realizar a conversão, a necessidade de um converter. Independente disso ai, preferi passar a string toda e trata la. Nesse caso ai colocando dessa forma, somente o id vai passar como string, bastando converte lo para int ao invés de fazer como fiz utilizando o raplaceAll.

O que mudou foi que, ao inves de passar todo o caminho, irá passar somente o id, é até melhor pra falar a verdade. Mesmo assim ainda continua valendo minha solução. Não há a necessidade do converter.

D

Olá, bom dia !

Não, não funciona !
SelectOneMenu não possui o atributo itemValue, correto ! Quem possui esse atributo ai é o selectItem e selectItems. Quando eu seleciono um valor na combo, quem captura esse valor selecionado é o SelectOneMenu e com isso tenho o atributo Value para pegar esse retorno, e ai volta no que contei acima.
Faça os testes você mesmo e verá o que estou falando.
Camarada, se você referenciar o objeto como sendo o alvo do selectOneMenu, com certeza isso não funcionará. Agora, se você apontar para o

<h:selectOneMenu value="#{meuBean.pivo.id}">
    <f:selectItems var="pv" value="#{meuBean.listaDePivos}" itemValue="#{pv.id}" itemLabel="#{pv.campoParaLabel}"/>
</h:selectOneMenu>

Funcionará melhor que fazer toda a gambiarra que você propôs (desde que o atributo pivo em meuBean não seja nulo).
Caso contrário, ainda prefiro o converter.
Faça os testes e veja o que eu estou falando.

D

E isso aqui só funciona se você tiver sobrescrito o método toString para que ele tenha essa saída.
Caso você tenha feito a sobrescrição do toString de outra maneira ou não o faça, isso nunca acontecerá.

F

drsmachado:
Frapout:

Quando a string é setada, ela vem da seguinte forma: br.com.embrapa.moscabranca.Pivo[ idPivo=1 ]

E isso aqui só funciona se você tiver sobrescrito o método toString para que ele tenha essa saída.
Caso você tenha feito a sobrescrição do toString de outra maneira ou não o faça, isso nunca acontecerá.

Não, não sobescrevi método algum. E sim, funciona e funcionou.
Fiz os testes e é o q disse no post acima. Indicando o id, melhorou pra mim pois estou pegando apenas o id como string agora, bastando apenas converte lo direto no meu ManagedBean, sem converter.

F

Valew cara,

Agora não preciso de usar o raplaceAll. Que cabeça, nem tinha me atentado para isso. Colocando do jeito q tu disse agora vem somente o id como string, bastando apenas converte lo, dentro do meu proprio managed bean.
È bem mais simples. Faça o teste pra vc ver.
A String vem daquela forma mesmo, serio mesmo, se eu deixar em itemValue o objeto todo ao inves de indicar o id.

Valew cara !!

D

Frapout:
Valew cara,

Agora não preciso de usar o raplaceAll. Que cabeça, nem tinha me atentado para isso. Colocando do jeito q tu disse agora vem somente o id como string, bastando apenas converte lo, dentro do meu proprio managed bean.
È bem mais simples. Faça o teste pra vc ver.
A String vem daquela forma mesmo, serio mesmo, se eu deixar em itemValue o objeto todo ao inves de indicar o id.
Valew cara !!


Camarada, quando você define um objeto como itemValue do selectItems ele será colocado no formato do seu respectivo método toString.
Por padrão, da classe Object, este método retorna o nome completo da classe + @ + uma sequência numérica.
Para que ele traga um atributo e o seu respectivo valor, o método deve ter sido sobrescrito.
Com o objetivo de provar o que eu estou dizendo, fiz um pequeno projeto contendo dados da forma que você diz ter feito (um Bean sem o método toString) e outro com o método toString.
Não fiz nada diferente do que você disse ter feito, apenas acrescentei o método toString sobrescrito.
Logo, veja como fica o html gerado após o processamento do arquivo xhtml:

&lt;!DOCTYPE html&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;
&lt;form id="j_idt5" name="j_idt5" method="post" action="/proj_prova/teste.jsf" enctype="application/x-www-form-urlencoded"&gt;
&lt;input type="hidden" name="j_idt5" value="j_idt5" /&gt;
&lt;select name="j_idt5:j_idt6" size="1"&gt;	&lt;option value="model.Bean@e6a29e"&gt;Bean: 1&lt;/option&gt;
	&lt;option value="model.Bean@1be40de"&gt;Bean: 2&lt;/option&gt;
	&lt;option value="model.Bean@194bd0c"&gt;Bean: 3&lt;/option&gt;
	&lt;option value="model.Bean@793f4"&gt;Bean: 4&lt;/option&gt;
	&lt;option value="model.Bean@182a44c"&gt;Bean: 5&lt;/option&gt;
&lt;/select&gt;&lt;select name="j_idt5:j_idt8" size="1"&gt;	&lt;option value="1"&gt;Bean: 1&lt;/option&gt;
	&lt;option value="2"&gt;Bean: 2&lt;/option&gt;
	&lt;option value="3"&gt;Bean: 3&lt;/option&gt;
	&lt;option value="4"&gt;Bean: 4&lt;/option&gt;
	&lt;option value="5"&gt;Bean: 5&lt;/option&gt;
&lt;/select&gt;&lt;input type="submit" name="j_idt5:j_idt10" value="Processar" /&gt;&lt;input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="-7838089237436510379:8825750935041399297" autocomplete="off" /&gt;
&lt;/form&gt;&lt;/body&gt; 
&lt;/html&gt;

Notou a diferença?
Segue anexo o projeto, execute-o e veja a diferença.
Ah, lógico que não será possível testar, visto que, segundo o que você disse, teremos um erro de validação, pois o valor referente ao primeiro selectOneMenu será inválido, pelo formato do mesmo.

F

drsmachado:
Frapout:
Valew cara,

Agora não preciso de usar o raplaceAll. Que cabeça, nem tinha me atentado para isso. Colocando do jeito q tu disse agora vem somente o id como string, bastando apenas converte lo, dentro do meu proprio managed bean.
È bem mais simples. Faça o teste pra vc ver.
A String vem daquela forma mesmo, serio mesmo, se eu deixar em itemValue o objeto todo ao inves de indicar o id.
Valew cara !!


Camarada, quando você define um objeto como itemValue do selectItems ele será colocado no formato do seu respectivo método toString.
Por padrão, da classe Object, este método retorna o nome completo da classe + @ + uma sequência numérica.
Para que ele traga um atributo e o seu respectivo valor, o método deve ter sido sobrescrito.
Com o objetivo de provar o que eu estou dizendo, fiz um pequeno projeto contendo dados da forma que você diz ter feito (um Bean sem o método toString) e outro com o método toString.
Não fiz nada diferente do que você disse ter feito, apenas acrescentei o método toString sobrescrito.
Logo, veja como fica o html gerado após o processamento do arquivo xhtml:

&lt;!DOCTYPE html&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;
&lt;form id="j_idt5" name="j_idt5" method="post" action="/proj_prova/teste.jsf" enctype="application/x-www-form-urlencoded"&gt;
&lt;input type="hidden" name="j_idt5" value="j_idt5" /&gt;
&lt;select name="j_idt5:j_idt6" size="1"&gt;	&lt;option value="model.Bean@e6a29e"&gt;Bean: 1&lt;/option&gt;
	&lt;option value="model.Bean@1be40de"&gt;Bean: 2&lt;/option&gt;
	&lt;option value="model.Bean@194bd0c"&gt;Bean: 3&lt;/option&gt;
	&lt;option value="model.Bean@793f4"&gt;Bean: 4&lt;/option&gt;
	&lt;option value="model.Bean@182a44c"&gt;Bean: 5&lt;/option&gt;
&lt;/select&gt;&lt;select name="j_idt5:j_idt8" size="1"&gt;	&lt;option value="1"&gt;Bean: 1&lt;/option&gt;
	&lt;option value="2"&gt;Bean: 2&lt;/option&gt;
	&lt;option value="3"&gt;Bean: 3&lt;/option&gt;
	&lt;option value="4"&gt;Bean: 4&lt;/option&gt;
	&lt;option value="5"&gt;Bean: 5&lt;/option&gt;
&lt;/select&gt;&lt;input type="submit" name="j_idt5:j_idt10" value="Processar" /&gt;&lt;input type="hidden" name="javax.faces.ViewState" id="javax.faces.ViewState" value="-7838089237436510379:8825750935041399297" autocomplete="off" /&gt;
&lt;/form&gt;&lt;/body&gt; 
&lt;/html&gt;

Notou a diferença?
Segue anexo o projeto, execute-o e veja a diferença.
Ah, lógico que não será possível testar, visto que, segundo o que você disse, teremos um erro de validação, pois o valor referente ao primeiro selectOneMenu será inválido, pelo formato do mesmo.

Ok camarada !
Você tem total razão no que está se propondo a me provar sobre esta questão do toString(). Concordo !!
Sou humilde para ver isso.
Mas você não está parando para analisar a minha solução. Ou eu não estou sabendo dizer o que fiz, camarada, ou entao.
Quando eu disse que funcionou, é porque funcionou.
Não tem o porque eu mentir ou inventar alguma coisa, sendo que testei o que fiz … inlógico isso … você não concorda ?
Testei aqui o que você fez, e tu tem razão, eu até já sabia disso. Mas a forma que fiz, não precisei sobrescrever nada, em fim, funcionou.
So postei algo que julguei um pouco mais simples.

Encerro meus comentários por aqui !

Abraços amigo !!

Criado 10 de julho de 2013
Ultima resposta 11 de jul. de 2013
Respostas 8
Participantes 2