Populando SelectOneMenu com dados do banco e salvando

Olá pessoal, eu preciso fazer uma tela de cadastro de matrícula, onde entro com informações iniciais do aluno e seleciono o Curso que ele vai fazer (cursos que já estão cadastrados no sistema). Eu to conseguindo puxar os dados do banco e mostrar no SelectOneMenu mas quando eu clico em salvar, não aparece nenhum erro, o SelectOneMenu apenas fica contornado em vermelho e nada é gravado no banco… Aalguém poderia me ajudar? vou mostrar umas partes dos códigos…

tela cadMatricula

[code]
<h:form>

		<p:panelGrid id="gridMatricula" styleClass="semBorda">
   		    <f:facet name="header">
   		       <p:row>
           			<p:column colspan="3" style="width:100% font-size:18px"> CADASTRAR MATRÍCULA </p:column>
       	   	    </p:row>  
   		    </f:facet>
           <p:row>
       			<p:column colspan="3" style="width:100% font-size:10px"> <div align="right">STATUS: <p:selectBooleanCheckbox/></div> </p:column>
       	   </p:row>
       	   <p:row>
       			<p:column style="width:50% font-size:8px">Matrícula</p:column>
       			<p:column style="width:50% font-size:8px" colspan="2">Nome</p:column>
       	   </p:row>
       	   <p:row>
       	   		<p:column><p:inputText value="#{MBAluno.beanAluno.matriculaAluno}" /></p:column>
       			<p:column colspan="2"><p:inputText value="#{MBAluno.beanAluno.nomeAluno}" size="60" /></p:column>
       	   </p:row>
       	   <p:row>
       			<p:column style="width:50% font-size:8px">Dt Nascimento</p:column>
       			<p:column style="width:50% font-size:8px">Curso</p:column>
       			<p:column style="width:50% font-size:8px">Senha</p:column>           			
       	   </p:row>
       	   <p:row>
				<p:column><p:inputMask mask="99/99/9999" value="#{MBAluno.dtNasc}"/></p:column>           	   
       			<p:column>
					<p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}" converter="cursoConverter">
						<f:selectItem itemLabel="-Selecione um curso" itemValue=""/>
						<f:selectItems value="#{MBCurso.selectCursos}" var="curso" 
										itemLabel="#{curso.nomeCurso}" itemValue="#{curso}"/>
					</p:selectOneMenu>           	           	
       			</p:column>
       			<p:column><p:password value="#{MBAluno.beanAluno.senhaAluno}" size="15" /></p:column>
       	   </p:row> 
    		<p:row>
       			<p:column colspan="3" style=" width:100% font-size:10px"> 
       			  <div align="center">
       			      <p:commandButton value="Salvar" icon="ui-icon-disk" actionListener="#{MBAluno.save}" 
       			      			update="gridMatricula"/>
       			      <p:button value="Cancelar" icon="ui-icon-cancel" type="reset"/>
       			  </div> 
       			</p:column>
       	   </p:row>
  		</p:panelGrid>
  	</div>
    </h:form>	
[/code]

MBCurso

public List<SelectItem> getSelectCursos(){ List<Curso> list = daoCurso.listar(); List<SelectItem> itens = new ArrayList<SelectItem>(list.size()); for(Curso c : list){ itens.add(new SelectItem(c.getCodCurso(), c.getNomeCurso())); } return itens; }

Aluno.class

//bi-directional many-to-one association to Curso @ManyToOne @JoinColumn(name="codCursoAluno") private Curso curso;

MBAluno

public void save() throws ParseException{ SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy"); Date data = new Date(format.parse(dtNasc).getTime()); beanAluno.setDtNascAluno(data); daoAluno.save(beanAluno); dtNasc = null; }

Obrigado desde já.

Alguém me ajuda por favor? Esqueci de postar o código do converter…

[code]@FacesConverter(“ConverterCurso”)
public class ConverterCurso implements Converter{
public List cursos;
DAOCurso daoCurso = new DAOCurso();

public ConverterCurso(){
	cursos = daoCurso.listar();
}
 
public Object getAsObject(FacesContext facesContext, UIComponent component, String value) {  
	if (value.trim().equals("")) {  
		return null;
	} 
	else{ 
		for (Curso curso : cursos) {  
			if (curso.getNomeCurso().equals(value)) {
				return curso;
			}
		}
	}
	return null;
}

public String getAsString(FacesContext facesContext, UIComponent component, Object value) {  
	if (value == null || value.equals("")) {  
		
		return "";  
	} 
	else {  
		return String.valueOf(((Curso)value).getNomeCurso()); 
	}  
}

}[/code]

dah um erro dizendo que o Valor do selectonemenu nao é válido…

E ai blz!

Cara é o seguinte, se a classe Aluno possui relacionamento com a classe Curso logo vc tem que salvar o ID da tabela curso na tabela aluno,
e não o nome do curso desta forma:

<p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}" converter="cursoConverter">  
                            <f:selectItem itemLabel="-Selecione um curso" itemValue=""/>  
                            <f:selectItems value="#{MBCurso.selectCursos}" var="curso"   
                                            itemLabel="#{curso.nomeCurso}" itemValue="#{curso.idCurso}"/>  
                        </p:selectOneMenu>  

ou seja, vc exibe o nome porém salva só o ID do curso.

fiz do jeito que você disse…e quando clico em Salvar, aparece uma mensagem de validação no SelectOneMenu dizendo “Erro de conversão ao definir o valor ‘10’ para ‘null Converter’.” Tem idéia do q seja? se o erro for no converter, me ajuda a arrumar ele por favor…

Agora eu adicionei o converter no SelectOneMenu e dah um erro de “java.lang.Integer cannot be cast to model.Curso”, não consigo resolver isso.

Eu uso um converter que você não precisa ir no banco para buscar a lista, eu acho bem mais simples e ele é genérico, para toda a aplicacões você só usa ele. Como está abaixo , você precisa colocar mais um atributo chamado “items” e o converter recebe essa lista lá através dessa linha de código: "component.getAttributes().get(“items”); " (que fica no converter).

É só copiar isso:

      <p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}" converter="objectConverter" items="#{MBCurso.selectCursos}">    
                            <f:selectItem itemLabel="-Selecione um curso" itemValue=""/>    
                            <f:selectItems value="#{MBCurso.selectCursos}" var="curso"     
                                            itemLabel="#{curso.nomeCurso}" itemValue="#{curso.idCurso}"/>    
     </p:selectOneMenu>    

E usar esse Converter agora:


@FacesConverter("objectConverter")
public class ObjectConverter implements Converter {
	
	

	@Override // Metodo que é chamado na inicialização do converter que pega os objetos da Lista e pega os ids deles através de reflexão e retorna esses ids em forma de String*/
	public String getAsString(FacesContext context, UIComponent component,Object value) {

		// Primeira linha em branco da combo caso exista, 
		// Aqui simulamos que o id desse campo em branco seja "-1"
		if (value == "") {
			return "-1";
		}
		
		//  Quando precisa renderizar uma combo com valor ainda não adquirido (null). 
		//  que é renderizada antes mesmo que um objeto seja selecionado.
		if(getIdByReflection(value) == null){
			return "-1";
		}
		
		// Retorna o id como Long, adquirido atraves de reflexão
		return getIdByReflection(value).toString();
	}	

	@Override // Quando eu seleciono um arquivo na combo por exemplo, ele pega o objeto e seta o valor do componente.
	public Object getAsObject(FacesContext context, UIComponent component, String value) {
		

		if (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);
		}
	}

	
	/** Retorna o objeto pelo id  */
	private Object findById(Collection collection, Long idToFind) {

		Object object = null;

		for (Object obj : collection) {
			Long id = getIdByReflection(obj);
			if (id.equals(idToFind)) {
				object = obj;
				break;
			}
		}
		return object;
	}
	
	private Long getIdByReflection(Object bean) {
		try {
			// Pega o Id do objeto
			Field idField = bean.getClass().getDeclaredField("id");
			idField.setAccessible(true);
			return (Long) idField.get(bean);
		} catch (Exception ex) {
			throw new ConverterException("Não foi possível obter a propriedade 'id' do item", ex);
		}
	}

}

Eu não estou dizendo que o outro exemplo do colega esteja errado, é só outra maneira de fazer a mesma coisa.

Vê se dá certo !

abraço

ta aparecendo isso como erro :

javax.faces.convert.ConverterException: Não foi possível obter a propriedade 'id' do item at converter.ConverterCurso.getIdByReflection(ConverterCurso.java:84) at converter.ConverterCurso.getAsString(ConverterCurso.java:34) at org.primefaces.renderkit.InputRenderer.getOptionAsString(InputRenderer.java:162) at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.encodeOption(SelectOneMenuRenderer.java:347) at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.encodeSelectItems(SelectOneMenuRenderer.java:333) at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.encodeInput(SelectOneMenuRenderer.java:114) at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.encodeMarkup(SelectOneMenuRenderer.java:91) at org.primefaces.component.selectonemenu.SelectOneMenuRenderer.encodeEnd(SelectOneMenuRenderer.java:65) at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:879) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646) at org.primefaces.component.panelgrid.PanelGridRenderer.encodeRow(PanelGridRenderer.java:143) at org.primefaces.component.panelgrid.PanelGridRenderer.encodeStaticBody(PanelGridRenderer.java:107) at org.primefaces.component.panelgrid.PanelGridRenderer.encodeBody(PanelGridRenderer.java:63) at org.primefaces.component.panelgrid.PanelGridRenderer.encodeEnd(PanelGridRenderer.java:49) at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:879) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1650) at javax.faces.render.Renderer.encodeChildren(Renderer.java:164) at javax.faces.component.UIComponentBase.encodeChildren(UIComponentBase.java:849) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1643) at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1646) at com.sun.faces.application.view.FaceletViewHandlingStrategy.renderView(FaceletViewHandlingStrategy.java:389) at com.sun.faces.application.view.MultiViewHandler.renderView(MultiViewHandler.java:127) at com.sun.faces.lifecycle.RenderResponsePhase.execute(RenderResponsePhase.java:117) at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:97) at com.sun.faces.lifecycle.LifecycleImpl.render(LifecycleImpl.java:135) at javax.faces.webapp.FacesServlet.service(FacesServlet.java:309) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99) at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1008) at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589) at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: java.lang.NoSuchFieldException: codCurso at java.lang.Class.getDeclaredField(Unknown Source) at converter.ConverterCurso.getIdByReflection(ConverterCurso.java:80) ... 42 more

Dá uma olhada se não tem nenhum item da lista com id nulo, e se o tipo do id é Long.

pra nao precisar mudar o banco, eu não posso apenas mudar de Long pra Integer lá no converter? outra coisa… vc passa uma lista de selectItem ou lista lah no SelectOneMenu? Obrigado!

Fala cara,

É passado ali uma lista de Object, vc pode ver que na linha 35 do converter ele seta uma Collection com essa lista e depois na linha 50 ele interage essa Collection em um for do tipo Object.
Eu acredito que não dê problema mudar no converter todas as Referencias de Long para Integer, tenta lá e depois avisa se deu certo.

Abs,

Gustavo

Fiz as modificações e continua dando o mesmo erro :
“Caused by: java.lang.NoSuchFieldException: id
at java.lang.Class.getDeclaredField(Unknown Source)
at converter.ConverterCurso.getIdByReflection(ConverterCurso.java:80)
… 42 more”

Não teria que trocar o “id” aqui nessa linha? Field idField = bean.getClass().getDeclaredField(“id”);

não sei oq tenho que colocar no lugar… “codCurso” ??

Oi JPedro,

Dando uma olhada no seu código eu estou vendo que o " #{MBCurso.selectCursos} " continua indo sem id, porque no método getSelectCursos() você seta o CodCursos e NomeCursos como consta na linha 5 do seu MBCurso (" itens.add(new SelectItem(c.getCodCurso(), c.getNomeCurso())); "), e o Converter precisa desse id.

Debuga o Converter e vê exatamente o que está acontecendo.

me desculpe mas oq eh esse id entao? eu pensava q vc se referia a chave primária do meu objeto. Não sei como passar esse id… pode me ajudar?

Vamos lá,

A sua Classe Curso tem um atributo chamado id ?

Quando você traz a lista do banco nessa linha :

 List<Curso> list = daoCurso.listar();  

… nesse “list” todos os itens estão vindo com esse id populado ?

Posta aqui depois esse seu método “daoCurso.listar()” .

Caso essa classe não tenha um atributo id crie um para facilitar no uso do converter.

private Long id;
//getters e setters

… e popule ele no método listar.

Outra coisa, porque vc criou uma classe “SelectItem” , ao inves de usar o atributo “list” do retorno do método listar. Você pode usar esse “list” direto para listar os itens da combo.


private List<Curso> cursosSelecionados;

...
 this.cursosSelecionados = daoCurso.listar();  
...
     

<p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}" converter="objectConverter" items="#{MBCurso.cursosSelecionados}">      
                       <f:selectItem itemLabel="-Selecione um curso" itemValue=""/>      
                       <f:selectItems value="#{MBCurso.cursosSelecionados}" var="curso"       
                                       itemLabel="#{curso.nomeCurso}" itemValue="#{curso.idCurso}"/>      
</p:selectOneMenu> 

abs

Entendi Gustavo…realmente nao tem esse atributo na minha classe Curso. Tem o atributo codCurso. Já experimentei passar “codCurso” como argumento do “getDeclaredField()” mas acontece o msmo erro.

Vou tentar mais um pouco… obrigado pela ajuda!

Cara, desculpa. Vendo o seu código de novo, eu achei o erro … vc está passando no “itemValue” o id, sendo que nesse caso usando o converter, vc tem que passar o objeto mesmo . Pois o converter está esperando um objeto com id ou codCurso , não um objeto Long Id cru.

Então ficaria:


<p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}" converter="objectConverter" items="#{MBCurso.cursosSelecionados}">        
                       <f:selectItem itemLabel="-Selecione um curso" itemValue=""/>        
                       <f:selectItems value="#{MBCurso.cursosSelecionados}" var="curso"         
                                       itemLabel="#{curso.nomeCurso}" itemValue="#{curso}"/>        
</p:selectOneMenu> 

Tentá lá

To quase desistindo… vou mostrar meu código novamente pq fiz algumas alterações e agora pelo menos ta aparecendo uma mensagem de erro nova. No SelectOneMenu aparece essa mensagem quando tento salvar: “{0}: Ocorreu um erro de conversão.” O problema é q não aparece nenhuma stacktrace.

cadMatricula

[code]
<h:form>

		<p:panelGrid id="gridMatricula" styleClass="semBorda">
   		    <f:facet name="header">
   		       <p:row>
           			<p:column colspan="3" style="width:100% font-size:18px"> CADASTRAR MATRÍCULA </p:column>
       	   	    </p:row>  
   		    </f:facet>
           <p:row>
       			<p:column colspan="3" style="width:100% font-size:10px"> <div align="right">STATUS: <p:selectBooleanCheckbox/></div> </p:column>
       	   </p:row>
       	   <p:row>
       			<p:column style="width:50% font-size:8px">Matrícula</p:column>
       			<p:column style="width:50% font-size:8px" colspan="2">Nome</p:column>
       	   </p:row>
       	   <p:row>
       	   		<p:column><p:inputText value="#{MBAluno.beanAluno.matriculaAluno}" /></p:column>
       			<p:column colspan="2"><p:inputText value="#{MBAluno.beanAluno.nomeAluno}" size="60" /></p:column>
       	   </p:row>
       	   <p:row>
       			<p:column style="width:50% font-size:8px">Dt Nascimento</p:column>
       			<p:column style="width:50% font-size:8px">Curso</p:column>
       			<p:column style="width:50% font-size:8px">Senha</p:column>           			
       	   </p:row>
       	   <p:row>
				<p:column><p:inputMask mask="99/99/9999" value="#{MBAluno.dtNasc}" required="true"/></p:column>           	   
       			<p:column>
					<p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}"
					require="true" requiredMessage="Campo obrigatório!" converter="cursoConverter">
						<f:selectItem itemLabel="-Selecione um curso" itemValue=""/>
						<f:selectItems value="#{MBCurso.listaMenu}" var="curso" 
									itemLabel="#{curso.nomeCurso}" itemValue="#{curso}"/>
					</p:selectOneMenu>
					<p:message for="cur" display="text" />          	           	
       			</p:column>
       			<p:column><p:inputText value="#{MBAluno.beanAluno.senhaAluno}" size="15" /></p:column>
       	   </p:row> 
    		<p:row>
       			<p:column colspan="3" style=" width:100% font-size:10px"> 
       			  <div align="center">
       			      <p:commandButton value="Salvar" icon="ui-icon-disk" action="#{MBAluno.save}" 
       			      			update="gridMatricula"/>
       			      <p:button value="Cancelar" icon="ui-icon-cancel" type="reset"/>
       			  </div> 
       			</p:column>
       	   </p:row>
  		</p:panelGrid>
  	</div>
    </h:form>	
[/code]

método usado no MBCurso

public List<Curso> getListaMenu(){ List<Curso> lista = daoCurso.listar(); return lista; }

método usado no DAOCurso

public List<Curso> listar(){ super.begin(); List<Curso> list = super.findAll(); super.commit(); return list; }

ModelDAO

@SuppressWarnings({ "unchecked", "rawtypes" }) public List<T> findAll() { CriteriaQuery cq = em.getCriteriaBuilder().createQuery(); cq.select(cq.from(entityClass)); return em.createQuery(cq).getResultList(); }

Aluno

[code]…

//bi-directional many-to-one association to Curso
@ManyToOne
@JoinColumn(name=“codCursoAluno”)
private Curso curso;
…[/code]

Curso

..... @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private int codCurso; .......

ConverterCurso

[code]@FacesConverter(value=“cursoConverter”, forClass=Curso.class)
public class ConverterCurso implements Converter{

@Override // Metodo que é chamado na inicialização do converter que pega os objetos da Lista e pega os ids deles através de reflexão e retorna esses ids em forma de String*/  
public String getAsString(FacesContext context, UIComponent component,Object value) {  

    // Primeira linha em branco da combo caso exista,   
    // Aqui simulamos que o id desse campo em branco seja "-1"  
    if (value == "") {  
        return "-1";  
    }  
      
    //  Quando precisa renderizar uma combo com valor ainda não adquirido (null).   
    //  que é renderizada antes mesmo que um objeto seja selecionado.  
    if(getIdByReflection(value) == null){  
        return "-1";  
    }  
      
    // Retorna o id como Long, adquirido atraves de reflexão  
    return getIdByReflection(value).toString();  
}     

@Override // Quando eu seleciono um arquivo na combo por exemplo, ele pega o objeto e seta o valor do componente.  
public Object getAsObject(FacesContext context, UIComponent component, String value) {  
      

    if (value.equals("")) {  
        return null;   
    }  

    try {  
        Integer id = Integer.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);  
    }  
}  

  
/** Retorna o objeto pelo id  */  
private Object findById(Collection collection, Integer idToFind) {  

    Object object = null;  

    for (Object obj : collection) {  
        Integer id = getIdByReflection(obj);  
        if (id.equals(idToFind)) {  
            object = obj;  
            break;  
        }  
    }  
    return object;  
}  
  
private Integer getIdByReflection(Object bean) {  
    try {  
        // Pega o Id do objeto  
        Field idField = bean.getClass().getDeclaredField("codCurso"); 
        idField.setAccessible(true);  
        return (Integer) idField.get(bean);  
    } catch (Exception ex) {  
        throw new ConverterException("Não foi possível obter a propriedade 'id' do item", ex);  
    }  
}  

}[/code]

método save do MBAluno

[code]…
public void save() throws ParseException{
SimpleDateFormat format = new SimpleDateFormat(“dd/MM/yyyy”);
Date data = new Date(format.parse(dtNasc).getTime());
beanAluno.setDtNascAluno(data);
daoAluno.save(beanAluno);
dtNasc = null;

}....[/code]

Desculpa encher o saco com esse problema… mas preciso resolver isso pra seguir em frente com o meu projeto de Engenharia de Software.
Obrigado

Fala JPedro,

Você esqueceu novamente de colocar o atributo “items” no seu componente selectOneMenu como mostrei lá em cima, você precisa colocar esse atributo com a lista que popula o componente para que o converter receba essa lista como mostra na linha 33 do converter.

Então ficaria,

<p:selectOneMenu id="cur" value="#{MBAluno.beanAluno.curso}" require="true" requiredMessage="Campo obrigatório!" converter="cursoConverter" items="#{MBCurso.listaMenu}">  
                            <f:selectItem itemLabel="-Selecione um curso" itemValue=""/>  
                            <f:selectItems value="#{MBCurso.listaMenu}" var="curso"  itemLabel="#{curso.nomeCurso}" itemValue="#{curso}"/>  
</p:selectOneMenu>  

Coloca um breakpoint no converter e confere o que ele está recebendo e vê qual é o erro, o funcionamento do converter não é tão complicado assim.

Abcs,

Gustavo