AutoComplete com JPA - Erro de conversão

Boa Tarde Pessoal,

Estou com um problema para utilizar o AutoComplete do PrimeFaces… Estou usando Eclipse Juno, PrimeFaces 3.3 e Hibernate 4.1.7.

Estou tentando fazer um AutoComplete de uma lista de bairros.

Primeiro eu populo minha lista de bairros e depois tem o meu método complete que iria verificar a existência do bairro.

Provavelmente um dos meus métodos esta errado, teria como me dar uma ajudinha??

Valeuu

	@SuppressWarnings("unchecked")
	public void preencheBairros() {
		this.bairros = new ArrayList<Bairro>();

		Session session = HibernateUtil.getSession();

		this.bairros = session.createCriteria(Bairro.class)
				.addOrder(Order.asc("nomeBairro")).list();

		session.close();
	}

	public List<String> complete(String busca) {
		List<String> retorno = new ArrayList<String>();
		for (Bairro bairro : bairros) {
			if (bairros.contains(busca)) {
				retorno.add(bairro);
			}
		}
		return retorno;
	}

O erro que aparece é esse: 

Nov 2, 2012 6:07:25 PM com.sun.faces.lifecycle.ApplyRequestValuesPhase execute
WARNING: /cadastroFuncionario.xhtml @51,63 completeMethod="#{cadastraFuncionariosBean.complete}": java.lang.NullPointerException
javax.el.ELException: /cadastroFuncionario.xhtml @51,63 completeMethod="#{cadastraFuncionariosBean.complete}": java.lang.NullPointerException
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:111)
	at org.primefaces.component.autocomplete.AutoComplete.broadcast(AutoComplete.java:340)
	at javax.faces.component.UIViewRoot.broadcastEvents(UIViewRoot.java:794)

// restante do erro...

Modifiquei meus métodos e criei um conversor. Mas agora esta dando o seguinte erro:

Nov 3, 2012 4:54:11 PM com.sun.faces.context.PartialViewContextImpl$PhaseAwareVisitCallback visit
SEVERE: java.lang.ClassCastException: java.lang.String cannot be cast to modelo.Bairro

Meus métodos ficaram assim:

	public List<Bairro> complete(String busca) throws Exception {
		this.bairros = funcionarioDao.listaTodos();
		List<Bairro> complete = new ArrayList<Bairro>();
		try {
			for (Bairro fore : this.bairros) {
				if (fore.getNomeBairro().contains(busca)) {
					complete.add(fore);
				}
			}
		} catch (Exception e) {
			FacesUtil.adiconarMensagem(FacesMessage.SEVERITY_ERROR, "Erro.",
					"Erro na listagem de bairros");
			e.printStackTrace();
		}
		return complete;
	}

Conversor

@FacesConverter(value = "bairroConverter")
public class BairroConverter implements Converter {

	@Override
	public Object getAsObject(FacesContext context, UIComponent component,
			String value) {
		FuncionarioDao funcionarioDao = new FuncionarioDao();
		Bairro bairro = null;
		try {
			bairro = funcionarioDao.buscaPorNome(value);
		} catch (Exception e) {
			FacesUtil.adiconarMensagem(FacesMessage.SEVERITY_FATAL,
					"Erro grave!!", "Erro no conversor de bairros");
			e.printStackTrace();
		}
		return bairro;
	}

	@Override
	public String getAsString(FacesContext context, UIComponent component,
			Object value) {
		Bairro bairro = new Bairro();
		bairro = (Bairro) value;
		return bairro.getNomeBairro();
	}

Não sei onde o que possa ser esse erro…

Poste aqui o código do xhtml com a chamada do autocomplete.

No teu complete tente colocar isso para ver se altera algo:

if (busca == null){ busca = ""; }

Aqui tem um exemplo de autocomplete funcionando: Aplicação Web Completa Tomcat JSF Primefaces JPA Hibernate.

[quote=edudebom]Poste aqui o código do xhtml com a chamada do autocomplete.

No teu complete tente colocar isso para ver se altera algo:

if (busca == null){ busca = ""; }[/quote]

Segue abaixo o xhtml:

					<p:autoComplete value="#{cadastraFuncionariosBean.bairro}"
						completeMethod="#{cadastraFuncionariosBean.complete}" var="bairro"
						itemLabel="#{bairro.nomeBairro}" itemValue="bairro"
						converter="bairroConverter" />

Eu alterei tambem o meu conversor, deixei dessa forma:

		Bairro bairro = new Bairro();
		try {
			bairro = (Bairro) value;
		} catch (Exception e) {
			FacesUtil.adiconarMensagem(FacesMessage.SEVERITY_FATAL, "Erro.",
					"Erro no conversor.");
			System.out.println("Erro na conversão");
			e.printStackTrace();
		}
		return bairro.getNomeBairro();
	}

O erro:

java.lang.ClassCastException: java.lang.String cannot be cast to modelo.Bairro
	at converter.BairroConverter.getAsString(BairroConverter.java:38)
	at org.primefaces.component.autocomplete.AutoCompleteRenderer.encodeSuggestionsAsList(AutoCompleteRenderer.java:434)
	at org.primefaces.component.autocomplete.AutoCompleteRenderer.encodeSuggestions(AutoCompleteRenderer.java:366)
	at org.primefaces.component.autocomplete.AutoCompleteRenderer.encodeResults(AutoCompleteRenderer.java:116)
Erro na conversão
	at org.primefaces.component.autocomplete.AutoCompleteRenderer.encodeEnd(AutoCompleteRenderer.java:98)

Só isso serve?

vou testar isso que voce me falou…

Mude para

itemValue="#{bairro}"

[quote=edudebom]Mude para

itemValue="#{bairro}"

Era isso mesmo! Agora parou de dar o erro… nem acredito que era só isso… Pura falta de atenção minha.
O problema agora é que ele esta adicionando Null na tabela de bairro. Queria que ele já vinculasse o id do bairro existente… Já não era para fazer isso edudebom??

Valeu pela ajuda!

Teu converter está fazendo uma busca por nome. Faça ele buscar pela chave primária.

Hebert estou seguindo exemplo que voce citou mais estou me deparando com um erro na seguinte parte do conversor:

	@Override
	public Object getAsObject(FacesContext context, UIComponent component,
			String value) {
		FuncionarioDao funcionarioDao = new FuncionarioDao();
		int bairroID;
		try {
			bairroID = Integer.parseInt(value);
		} catch (NumberFormatException exception) {
			throw new ConverterException(new FacesMessage(
					FacesMessage.SEVERITY_ERROR, "Erro grave",
					"Erro no conversor"));

O erro:

java.lang.NumberFormatException: For input string: "Botafogo"
	at java.lang.NumberFormatException.forInputString(Unknown Source)
	at java.lang.Integer.parseInt(Unknown Source)
	at java.lang.Integer.parseInt(Unknown Source)
	at converter.BairroConverter.getAsObject(BairroConverter.java:24)
	at org.primefaces.component.autocomplete.AutoCompleteRenderer.getConvertedValue(AutoCompleteRenderer.java:533)
	at javax.faces.component.UIInput.getConvertedValue(UIInput.java:1030)
	at javax.faces.component.UIInput.validate(UIInput.java:960)
	at javax.faces.component.UIInput.executeValidate(UIInput.java:1233)
	at javax.faces.component.UIInput.processValidators(UIInput.java:698)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at org.primefaces.component.fieldset.Fieldset.processValidators(Fieldset.java:197)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at org.primefaces.component.panel.Panel.processValidators(Panel.java:293)
	at javax.faces.component.UIForm.processValidators(UIForm.java:253)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at javax.faces.component.UIComponentBase.processValidators(UIComponentBase.java:1214)
	at javax.faces.component.UIViewRoot.processValidators(UIViewRoot.java:1172)
	at com.sun.faces.lifecycle.ProcessValidationsPhase.execute(ProcessValidationsPhase.java:76)
	at com.sun.faces.lifecycle.Phase.doPhase(Phase.java:101)
	at com.sun.faces.lifecycle.LifecycleImpl.execute(LifecycleImpl.java:118)
	at javax.faces.webapp.FacesServlet.service(FacesServlet.java:593)
	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:168)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
	at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
	at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1002)
	at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
	at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
	at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.lang.Thread.run(Unknown Source)

Sabe me dizer oque fiz de errado?

Uso assim:

Conversor

public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) { try { return jpa.findCidade(Integer.valueOf(arg2).longValue()); } catch (NumberFormatException e) { return new Cidade(); } }

Busca

public Cidade findCidade(Long id) { EntityManager em = getEntityManager(); try { return em.find(Cidade.class, id); } finally { em.close(); }
}

[quote=edudebom]Uso assim:

Conversor

public Object getAsObject(FacesContext arg0, UIComponent arg1, String arg2) { try { return jpa.findCidade(Integer.valueOf(arg2).longValue()); } catch (NumberFormatException e) { return new Cidade(); } }

Busca

public Cidade findCidade(Long id) { EntityManager em = getEntityManager(); try { return em.find(Cidade.class, id); } finally { em.close(); }
}[/quote]
edudebom,

nesse caso só dá pra fazer com JPA?
Não sei utilizar, estou tentando fazer em Hibernate mas não estou conseguindo tambem… Tem um exemplo que possa me passar?

Não precisa ser JPA. Você deve ter um BairroDao certo ? Faça uma pesquisa pelo id.

edudebom,

fiz um método que pesquise pelo id, o autocomplete até busca os bairros, mas na hora que adiciona acontece a mesma coisa que aconteceu com o GustavoSS ele adiciona o bairro como null ao invés de pegar o id do bairro existente.

Conversor:

	@Override
	public Object getAsObject(FacesContext context, UIComponent component,
			String value) {
		BairroDao bairroDao = new BairroDao();
		Bairro bairro = new Bairro();
		try {
			return bairroDao.buscaPorID(Integer.valueOf(value));
		} catch (Exception e) {
			e.printStackTrace();
		}
		return (new Bairro());
	}

Método:

	public Bairro buscaPorID(Integer id) {
		Bairro bairro = new Bairro();
		session = HibernateUtil.getSession();
		try {
			bairro = (Bairro) session.createCriteria(Bairro.class)
					.add(Restrictions.idEq(id)).uniqueResult();
		} catch (Exception e) {
			e.printStackTrace();
		}
		session.close();
		return bairro;
	}
}

Muda alguma coisa na hora de adicionar?

Veja no seu código fonte gerado do xhtml se os values do select estão chegando preenchidos.

Seria isso?

<ul class="ui-autocomplete-items ui-autocomplete-list ui-widget-content ui-widget ui-corner-all ui-helper-reset">
<li class="ui-autocomplete-item ui-autocomplete-list-item ui-corner-all" data-item-value="Bonsucesso" data-item-label="Bonsucesso">
<span class="ui-autocomplete-query">Bo</span>nsucesso</li>
<li class="ui-autocomplete-item ui-autocomplete-list-item ui-corner-all ui-state-highlight" data-item-value="Botafogo" data-item-label="Botafogo"><span class="ui-autocomplete-query">Bo</span>tafogo</li></ul>

ou isso?

<span id="form:bairroComplete" class="ui-autocomplete">
<input id="form:bairroComplete_input" name="form:bairroComplete_input" type="text" class="ui-autocomplete-input ui-inputfield ui-widget ui-state-default ui-corner-all" autocomplete="off" value="" role="textbox" aria-disabled="false" aria-readonly="false" aria-multiline="false">
<input id="form:bairroComplete_hinput" name="form:bairroComplete_hinput" type="hidden" autocomplete="off" value="Bonsucesso"></span>

Rode em modo debug e veja se no teu getAsObject está chegando o value e retornando o bairro corretamente.

edudebom,

o value esta chegando com a seguinte informação: “Botafogo”

pelo que vi ele não entra no método buscaPorID.
e da o seguinte erro:

java.lang.NumberFormatException: For input string: "Botafogo"
	at java.lang.NumberFormatException.forInputString(Unknown Source)
	at java.lang.Integer.parseInt(Unknown Source)
	at java.lang.Integer.valueOf(Unknown Source)
	at converter.BairroConverter.getAsObject(BairroConverter.java:25)

Converter:

	public Object getAsObject(FacesContext context, UIComponent component,
			String value) {
		BairroDao bairroDao = new BairroDao();
		Bairro bairro = new Bairro();
		try {
			return bairroDao.buscaPorID(Integer.valueOf(value));
		} catch (Exception e) {
			e.printStackTrace();
			return (new Bairro());
		}
	}

Metodo

	public Bairro buscaPorID(Integer id) {
		Bairro bairro = new Bairro();
		session = HibernateUtil.getSession();
		try {
			bairro = (Bairro) session.get(Bairro.class, id);
		} catch (Exception e) {
			e.printStackTrace();
		}
		session.close();
		return bairro;
	}

Tive um problema parecido ao tentar usar o autoComplete e acabei desistindo dele. Usei o selectOneMenu e acabei tendo praticamente o mesmo resultado.

O autocomplete até encontrava tudo, eu selecionava e no momento de busca-lo no banco ele passava uma variável nula para o meu ManagedBean e não conseguia localizá-lo no banco.

Mas ai eu não vou esbarrar no mesmo problema que é o conversor? Por que o selectOneMenu necessita de um conversor também né?

Tente

itemValue="#{bairro.suachaveprimaria}"

Se não funcionar cole aqui seu Bairro.java