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

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("[^0123456789]", "");
        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.

1 curtida

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?

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.

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.[/quote]
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.

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á.

[quote=drsmachado][quote=Frapout]
Quando a string é setada, ela vem da seguinte forma: br.com.embrapa.moscabranca.Pivo[ idPivo=1 ]
[/quote]
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á.

[/quote]

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.

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 !!

[quote=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 !![/quote]
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.

[quote=drsmachado][quote=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 !![/quote]
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.[/quote]

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 !!