SelectOneMenu JSF 2.0

Oie!

para preencher um selectOneMenu com dados do BD com JSF 1.2 eu preciso criar uma list de selectItem, e para pegar o item selecionado eu preciso fazer uma conversão.

já no JSF 2.0 ele aceita uma lista de Entity…Minha duvida é… eu preciso converter esse item selecionado?
eu acho que nao pois estou preenchendo o selectOneMenu ja com uma list de entity.
mas não está dando certo ele gera uma execeção.

[code]exception

javax.servlet.ServletException: null source
javax.faces.webapp.FacesServlet.service(FacesServlet.java:321)

root cause

java.lang.IllegalArgumentException: null source
java.util.EventObject.(Unknown Source)
javax.faces.event.SystemEvent.(SystemEvent.java:67)
javax.faces.event.ComponentSystemEvent.(ComponentSystemEvent.java:69)
javax.faces.event.PostRestoreStateEvent.(PostRestoreStateEvent.java:69)
com.sun.faces.lifecycle.RestoreViewPhase.deliverPostRestoreStateEvent(RestoreViewPhase.java:256)
com.sun.faces.lifecycle.RestoreViewPhase.execute(RestoreViewPhase.java:245)
com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97)
com.sun.faces.lifecycle.RestoreViewPhase.doPhase(RestoreViewPhase.java:107)
com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:114)
javax.faces.webapp.FacesServlet.service(FacesServlet.java:308)

[/code]

eu consigo preencher selectOneMenu…mas na hora de pegar o selecionado ele gera essa exceção.

Olá boa tarde!

Então, tive uns problema com combobox, no meu caso o problema era no conversor

mais vou ser se consigo te ajudar

o codigo da pagina

 <h:outputLabel  for="estado"  value="Uf:" />   
                  
     <h:selectOneMenu id="estado"  value="#{municipioC.municipio.estado}" >

           <f:selectItems value="#{estadoC.itemsAvailableSelectOne}"
              var="item" 
              itemValue="#{item}" 
              itemLabel="#{item.dsEstado}"            />
     </h:selectOneMenu>    	            

o Objeto item que no meu caso representa o Estado no momento de gravar precisa ser convertido então o JSF irá chamar
getAsObject veja o conversor abaixo e instanciar a classe controler para chamar o serviço que retornará o Objeto
o codigo tai abaixo.

    @FacesConverter(forClass = Estado.class)
    public static class EstadoControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
                        
                   
            EstadoController controller = (EstadoController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "estadoC");
            return controller.estadoService.findByID(getKey(value));
        }

        java.lang.String getKey(String value) {
            java.lang.String key;
            key = value;
            return key;
        }

Posta seu código ai.
Dê uma olhada em como eu faço … talvez ajude


<p:outputPanel id="Exercicio" >
    <p:growl id="consulta"/>
          <h:panelGrid columns="2" columnClasses="colunaEsquerda,colunaDireita" style="text-align: right;align:right; font-size: 14px;">	
							
	    <h:outputText value="Nome : " for="exercicio-nome"/>
  	   <p:inputText
  	 		   id="exercicio-nome"
  			required="true"
  			value="#{exercicioBean.exercicio.nome}"
  			size="30"
  			onkeydown="this.value = this.value.toUpperCase();"/>
  		
  		<h:outputText value="Grupo Muscular : " for="exercicio-grupo" />
  		<p:selectOneMenu id="exercicio-grupo" value="#{exercicioBean.gmID}" required="true">
		        <f:selectItems 
			                value="#{grupoMuscularBean.grupoMusculares}"
			                var="gm"
					itemLabel="#{gm.nome}"
					itemValue="#{gm.id}"/>
		</p:selectOneMenu>
  						  								
  	</h:panelGrid>
  						

[code]
public void adiciona(){

	System.out.println("ADICIONANDO EXERCICIO");
	if ( this.exercicio != null ){
		
		ELContext elContext = FacesContext.getCurrentInstance().getELContext();
		this.entityManager = (EntityManager) FacesContext.getCurrentInstance().getApplication().getELResolver().getValue(elContext, null, "entityManager");
		
		GrupoMuscularRepository grupoMuscularRepository = new GrupoMuscularRepository(this.entityManager);
		GrupoMuscular grupoM = grupoMuscularRepository.procura(this.gmID);
		
		this.exercicio.setGrupoM(grupoM);
		
		ExercicioRepository exercicioRepository = new ExercicioRepository(this.entityManager);
		exercicioRepository.adiciona(exercicio);
		
		this.exercicio = new Exercicio();
		this.exercicioSelecionado = new Exercicio();
		this.exercicios = null;
		
		FacesContext.getCurrentInstance().addMessage("exercicio:id",new FacesMessage("CADASTRADO COM SUCESSO"));
		
	}else{
		
		FacesContext.getCurrentInstance().addMessage("exercicio:id",new FacesMessage("PREENCHA O FORMULÁRIO"));
		
	}
}
[/code]

desculpe a demora é que estou de mudanças :stuck_out_tongue:

poise eu tentei dos 2 jeitos…o problema é que se eu preencher com uma lista de selectItem da certo…
mas se eu preencher com uma lista de cliente(jsf 2.0 suporta) quando eu clico no botão não acontece nada
como eu disse antes acho que não é necessário criar um conversor para esse caso ou estou errada?
para fazer o teste eu criei um conversor implementando o Converter. ae ele apresentou uma exceção…

[code]exceção:

exception
javax.servlet.ServletException: For input string: “[bean.Cliente@73s891950, bean. Cliente @2df50e72, bean. Cliente @bdf15e4, bean. Cliente @sdbbl1d2, bean. Cliente @456b7171]”
javax.faces.webapp.FacesServlet.service(FacesServlet.java:321)

root cause
java.lang.NumberFormatException: For input string: “[ bean.Cliente@73s891950, bean. Cliente @2df50e72, bean. Cliente @bdf15e4, bean. Cliente @sdbbl1d2, bean. Cliente @456b7171 ]”
java.lang.NumberFormatException.forInputString(Unknown Source)[/code]
o que acontece?
a minha jsp está passando não apenas o objeto selecionado mas todos os objetos da lista para o conversor… a execeção ocorre dentro do conversor na hora de setar os dados
dei um println no conversor para saber o que ele estava recebendo e realmente ele mostra o nome de todos os clientes.

selectonemenu:

<h:selectOneMenu value = "#{clienteBean.Cliente}" > <f:selectItem itemLabel = "SELECIONE" itemValue="" /> <f:selectItems value="#{ clienteBean .listaCliente }" var="a" itemLabel="#{a.nomeCliente}" itemValue="#{a.idCliente } " /> </h:selectOneMenu>

Olha estou vendo que vc esta passando o Nome do Cliente e o ID do cliente, isto não é necessario, vc precisa passar
o nome do Cliente e o Objeto Cliente.

no momento de Gravar o conversor deverá chamar o metodo getAsObject ou seja ira transformar em Objeto para que
possa ser salvo no banco,

vamos passo a passo então vou começar das classes entidade usando um exemplo de Municipio e Estado

trecho de codigo da classe Municipio.Java mostrando o relacionamento

	//bi-directional many-to-one association to Estado
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="id_estado")
	private Estado estado;		

Estado.java Observe o metodo toString porque ele será necessario

	@Id
	@Column(name="id_estado")
	private String idEstado;

	@Column(name="ds_estado")
	private String dsEstado;

	//bi-directional many-to-one association to Municipio
	@OneToMany(mappedBy="estado")
	private List<Municipio> municipios;


       @Override
       public String toString() {
        return dsEstado;
        }

Vamos agora relembrar como esta a minha pagina note que ela chama um metodo estadoC.itemsAvailableSelectOne
estadoC é o meu MB

       <h:outputLabel for="nome"  value="Nome:" />
       <h:inputText   id="nome"   value="#{municipioC.municipio.dsMunicipio}" style=" width : 450px;"/>	          

       <h:outputLabel  for="estado"  value="Uf:" />   
                  
       <h:selectOneMenu id="estado"  value="#{municipioC.municipio.estado}" >

               <f:selectItems value="#{estadoC.itemsAvailableSelectOne}"
                   var="item" 
                   itemValue="#{item}" 
                   itemLabel="#{item.dsEstado}"            />
               </h:selectOneMenu>    	            

Vamos ver um trecho de EstadoController.java


@ManagedBean(name="estadoC")
@SessionScoped
public class EstadoController {
	
	private Estado estado;
	private List<Estado> estadoLista;
	private int totalRegistros;
	
	@ManagedProperty(value = "#{estadoService}")
	private EstadoService estadoService;

        public SelectItem[] getItemsAvailableSelectOne() {
        
           return FacesUtil.getSelectItems(estadoService.findAll(), true);
	
          }	

    @FacesConverter(forClass = Estado.class)
    public static class EstadoControllerConverter implements Converter {

        public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {
            if (value == null || value.length() == 0) {
                return null;
            }
                        
                   
            EstadoController controller = (EstadoController) facesContext.getApplication().getELResolver().
                    getValue(facesContext.getELContext(), null, "estadoC");
            return controller.estadoService.findByID(getKey(value));
        }

so para não ficar duvidas vamos ver o metodo getSelectItems na classe FacesUtil
observe a variavel X que será o objeto Estado e x.toString() será a descricao do estado ( veja na classe Estado.java )

    public static SelectItem[] getSelectItems(List<?> entities, boolean selectOne) {
        int size = selectOne ? entities.size() + 1 : entities.size();
        SelectItem[] items = new SelectItem[size];
        int i = 0;
        if (selectOne) {
            items[0] = new SelectItem("", "---");
            i++;
        }
        for (Object x : entities) {
            items[i++] = new SelectItem(x, x.toString());
        }
        return items;
    }

bem… o que posso dizer mais… há reveja na pagina a tag
<h:selectOneMenu id=“estado” value="#{municipioC.municipio.estado}" >
observe que o MB municipioController.java nomeado para municipioC temos ai o atributo estado que faz parte de nossa entidade Municipio.Java

bem acho que tá tudo ai, o lance é o converter que esta em EstadoController.java
cheque isto no seu codigo que ira dar certo com Certeza.

Qualquer coisa é so mandar

vc não me compreendeu assim eu sei fazer… eu li um pdf(que falava sobre as novidades do jsf 2.0),e nele dizia que com com jsf 2.0 era possível preencher um selectonemenu com um list de entity e não de selectItem e que não havia a necessidade de fazer a conversão.
mas dei uma pesquisada…e as poucas respostas que eu encontrei diziam que não na certo que tem um bug nisso…

enão vou deixar de lado… :xmas obrigada pelo esforço de tentar me ajudar :wink:

Bjin

Oi tudo bem?

bem realmente não entendi mesmo que era só com um List ( acho que porque tudo começa com ele para depois vir o selectItem )
mais esta seria a primeira vez que tento ajudar alguem ( depois de um ano com Java ) .

Mais bem se realmente for um Bug… é esperar então. Um Abraço.

Robson Lira

luci.al, acabei de resolver este tipo de problema de uma forma bem simples e sem precisar do converter.

Apenas preenchi a lista de SelectItem colocando o indice.

Ex: Tenho uma aplicação que preciso cadastrar Logradouros. No entando, tenho outra tela que cadastra Tipos de Logradouro(Rua, Avenida). Quando vou cadastrar o logradouro, tenho um selectOneMenu que contem os Tipos de Logradouro cadastrados.

Então, deve-se carregar a lista de SelectItem assim:

lTl = new TipoLogradouroDAO().getList(); //busca a lista de Tipos de Logradouros cadastrados no banco.
        for(int i=0; i<lTl.size();i++){ //percorrer o indice do vector, posição por posição.
            listCombo.add(new SelectItem(lTl.get(i).getCodigo(), lTl.get(i).getAbreviatura()));
        }

onde, lTl é minha lista do tipo Logradouro e listCombo é minha lista do tipo SelectItem.

Faça um teste porfavor e caso tenha dúvidas, estou a disposição.