JSF: Converter e Bean Auto Complete

Olá pessoal, tudo bem?

Hoje vamos ver sobre Converters (utilizado em Select (o famoso “ComboBox”), e outros) e o Auto Complete (Auto Completar) de Beans através do eclipse.

Obs.: Irei utilizar o termo ComboBox (pois sei que outras tecnologias em sua grande maioria Desktop, como Delphi), nomeiam esse componente assim. Mas saiba que esse termo não é utilizado para HTML, o termo correto é select.

Antes, vamos começar com algumas configurações necessárias. Serei rápido em alguns detalhes de configurações e outros detalhes eu explicarei melhor.

Utilize os links para o download das bibliotecas JSF e JSTL que você poderá encontrar aqui Mojarra JSF e JSTL. Inclusive, no post JSF – Hello World, Auto Complete, é ensinado passo a passo como montar uma aplicação JSF.

Primeiro, vamos fazer o download de todas as bibliotecas necessárias (JSF e JSTL). Após concluir os downloads dos arquivos, copie apenas os arquivos do tipo “JAR” para dentro da pasta WEB-INF. (Esse passo a passo foi feito nos posts: JSF – Hello World, Auto Complete e Criando um WebServer).

Crie o seu projeto (Dynamic Web Project) com as configurações iguais a dessa imagem (note que estou utilizando o Tomcat e o Eclipse mais recente). Aperte “Next” até aparecer esta tela e escolha a opção “Disable Library Configuration”.

Vamos agora adicionar as bibliotecas ao build path. Botão direito sobre o projeto > Properties. Depois clique em Build Path, e por último “Add Jars”.

Selecione na janela – que abriu – os arquivos “*.jar” que se encontram na pasta WEB-INF/lib. E depois aperte OK e feche a janela de configurações.

Precisamos alterar o “web.xml” (caso o Eclipse não tenha criado esse arquivo para você, basta criar um arquivo dentro da pasta “WEB-INF” e colar o texto abaixo).

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>faces/index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

Vamos criar uma pagina inicial apenas para ver se está tudo funcionando? Crie um arquivo chamado “index.xhtml” dentro da pasta “WebContent”. Após criar esse arquivo cole o código abaixo dentro do arquivo (pode apagar qualquer outro código que esteja lá dentro).

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>Hellow World JSF 2.0</title>
    </h:head>

    <h:body>
        <h:form>
            <h:outputText value="Hello"/>
        </h:form>
    </h:body>
</html>

Inicie sua aplicação para que ela seja executada no servidor (caso você não saiba, veja aqui Criando um WebServer). Digite o seguinte endereço no seu browser http://localhost:8080/PostJSF/. A página index aparecerá exibindo o texto Hello. Caso não exiba, volte e refaça os passos acima.

Para que serve um Converter? Vamos ver na prática? Vamos criar um exemplo simples de selecionar um usuário de uma lista e exibir seu nome em outra tela. E um erro acontecerá…

Crie uma classe Java chamada User no pacote “com”. Ela terá as seguintes informações:

package com;

public class User {

    public User(){

    }

    public User(String userName, String email){
        this.userName = userName;
        this.email = email;
    }

    private String userName;
    private String email;

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

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

Vamos criar uma classe controladora (UserMB), essa classe terá um atributo do tipo User e irá exibir a hora atual em outra página.

package com;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean(name="userMB")
@RequestScoped
public class UserMB {

    private User user;
    private Map users;

    public UserMB(){
        users = new HashMap();
        users.put("Name 01", new User("Name 01", "Email 01"));
        users.put("Name 02", new User("Name 02", "Email 02"));
        users.put("Name 03", new User("Name 03", "Email 03"));
        users.put("Name 04", new User("Name 04", "Email 04"));
        users.put("Name 05", new User("Name 05", "Email 05"));
    }

    public String showName(){
        return "show.xhtml";
    }

    public Date getServerTime(){
        return new Date();
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List getUsers() {
        return new ArrayList(users.values());
    }

    public User getUserByName(String userName){
        return users.get(userName);
    }
}

Nós populamos um mapa com usuários, mas essa informação poderia ter sua origem do banco de dados.

Vamos alterar novamente o “index.xhtml” para ficar conforme o código abaixo. Vamos adicionar um select contendo opções de vários usuários:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>JSF 2.0</title>
    </h:head>

    <h:body>
        <h:form>
            <h:outputText value="Hello"/><br/>

            <h:selectOneMenu value="#{userMB.user}">
                 <f:selectItems value="#{userMB.users}"/>
            </h:selectOneMenu>

            <h:commandButton action="show.jsf" value="Go!"/>
        </h:form>
    </h:body>
</html>

Vamos criar também um arquivo chamado “show.xhtml” para exibir o usuário selecionado:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>JSF 2.0</title>
    </h:head>

    <h:body>
        <h:form>
            <h:outputText value="#{userMB.user.userName}"/><br/>
            <h:outputText value="#{userMB.serverTime}"/>
        </h:form>
    </h:body>
</html>

Um código bem simples e objetivo. Selecionamos um usuário na tela inicial e o exibimos o nome dele na tela seguinte junto com a data do servidor.

Vamos executar a aplicação novamente e ver o resultado?

Note que um erro apareceu no console: “severity=(ERROR 2), summary=(Erro de conversão ao definir o valor para ‘null Converter’. ), detail=(Erro de conversão ao definir o valor para ‘null Converter’. )

Precisamos utilizar um conversor para que o JSF possa entender que a informação selecionada é do tipo User. Para criar o conversor, vamos criar uma classe Java onde ela implementará a interface Converter que têm dois métodos abstratos.
Nosso converter terá a anotação @FacesConverter onde o servidor, ao iniciar a apliação, irá identificar essa classe, deixando-a disponível para nossa view.

package com;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.FacesConverter;

@FacesConverter(value="userConverter")
public class UserConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext arg0, UIComponent arg1, String key) {
        FacesContext context = FacesContext.getCurrentInstance();
        UserMB userMB = (UserMB) context.getELContext().getELResolver().getValue(context.getELContext(), null, "userMB");

        return userMB.getUserByName(key);
    }

    @Override
    public String getAsString(FacesContext arg0, UIComponent arg1, Object arg2) {
        return arg2.toString();
    }
}

E para finalizar, basta atualizar o arquivo “index.xhtml” para que agora ele passe a identificar o nosso converter.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"
        xmlns:f="http://java.sun.com/jsf/core">

    <h:head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
        <title>JSF 2.0</title>
    </h:head>

    <h:body>
        <h:form>
            <h:outputText value="Hello"/><br/>

            <h:selectOneMenu value="#{userMB.user}">
                 <f:selectItems value="#{userMB.users}"/>
                 <f:converter converterId="userConverter"/>
            </h:selectOneMenu>

            <h:commandButton action="#{userMB.showName}" value="Go!"/>
        </h:form>
    </h:body>
</html>

Vamos rodar nossa aplicação novamente e ver o que acontece?

Repare que no código do Converter é feito uma consulta ao Map de usuários, caso fosse necessário, utilizariamos uma classe Injetada no Managed Bean para consultar o banco de dados. Atenção: Um converter não fará Injeção alguma de recursos, não adianta colocar @EJB ou qualquer outra anotação. Por isso criei o acesso direto à um Managed Bean.

Um Converter é utilizado quando queremos atribuir um objeto (através de setter ou método parecido) vindo de um select (ComboBox) ou outro objeto de escolha. Em nosso caso, o setter do objeto User é chamado e o converter entra em ação, convertendo o ID que vem do select (em nosso caso o nome do usuário) pelo método “getAsObject”, que realiza uma busca pelo objeto real.

E como ativar o Auto Complete do Eclipse quando se trata de uma classe Java? O Auto Complete funciona sempre com uma classe que o JSF tem controle, MangedBean, Bundle, etc. Você já pode ter notado que as tags já estão com o Auto Complete funcionando. (Caso não tenha percebido, abra um arquivo do tipo xhtml e digite “<h:” e aperte ctrl+espaço)

Para ativar o Auto Complete nas classes Java, por exemplo, após escrever “#{userMB.}” ser exibida uma lista de opções após o ponto, vamos ter que alterar nosso Managed Bean e o arquivo “faces-config.xml”.

A alteração no arquivo UserMB será simples, basta retirar as anotações “@ManagedBean” e “@RequestScoped”. Nossa classe ficará assim:

package com;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UserMB {

    private User user;
    private Map users;

    public UserMB(){
        users = new HashMap();
        users.put("Name 01", new User("Name 01", "Email 01"));
        users.put("Name 02", new User("Name 02", "Email 02"));
        users.put("Name 03", new User("Name 03", "Email 03"));
        users.put("Name 04", new User("Name 04", "Email 04"));
        users.put("Name 05", new User("Name 05", "Email 05"));
    }

    public String showName(){
        return "show.xhtml";
    }

    public Date getServerTime(){
        return new Date();
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public List getUsers() {
        return new ArrayList(users.values());
    }

    public User getUserByName(String userName){
        return users.get(userName);
    }
}

E agora, vamos editar o arquivo “faces-config.xml”. Será necessário adicionar o managed bean no arquivo xml que fica na aba ManagedBean.

Selecione a opção “request” e depois clique em “add”. Digite UserMB (para que nossa classe apareça) e depois clique em “Finish” e salve as alterações.

Abra o arquivo “show.xhtml” e dentro da EL “#{userMB.user}” digite um . (ponto) após o user e aperte ctrl+espaço para ver a “mágica” acontecer.

Não ache que você está regredindo ao fazer todas as anotações por xml. Existem práticas de Design Pattern que pregam que se você utilizar anotações você estará “invadindo” uma classe para que ela seja configurada para algo que ela não precisa saber. Esse é um dos motivos que o Spring/Hibernate/JPA/JSF permitem o uso de anotações eo uso de XML para configurações. E note que a única coisa que fizemos foi informar qual classe seria nosso Managed Bean e pronto.

Você poderá editar seu “faces-config.xml” através dessa interface que é fácil de utilizar.

Um pequeno detalhe também é que o seu Project Facates tem que estar marcado como JSF. Nesse post é ensinado a alterar o Project Facets: JSF – Hello World, Auto Complete

Espero que esse post possa te ajudar.

Qualquer dúvida, basta falar.

Até a próxima

11 thoughts on “JSF: Converter e Bean Auto Complete

  1. Herbert, mais uma vez um post salvador seu…. se não é aqui é no forum do GUJ… valeu pela ajuda. Agora me tira uma dúvida. Sou iniciante (BEM) em JSF, porque temos que fazer um converter se eu “dependura” no selectonemenu uma lista de objetos? No submit do form o objeto que está selecionado no selectonemenu não iria para o atributo que representa o objeto?

    • Marcelo, boa tarde.

      No padrão não só JSF, mas web objetos não são enviados ou recebidos mas apenas texto.

      Ao apertar o subimt, seja com JSF ou JSP ou Struts apenas texto é enviado e não objetos.

      Para não precisar de um converter ao invés de fazer itemValue=”#{carro}” faça itemValue=”#{carro.id}” e aponte para um int. Desse modo você terá o id já populado no seu ManagedBean e depois você poderá fazer a consulta no db. [=

      Espero ter ajudado, até mais.

      • Olá Hebert,

        Eu utilizo este padrão nos meus MB`s. Os combos carregam perfeitamente, porém quando clico no submit, eles ficam em vermelho e nada acontece.
        Tens alguma ideia do que possa ser?

        Abraço

        • Olá, boa tarde.

          Coloque um componente h:messages na tela, alguma mensagem de erro está sendo retornada mas não exibida para você.

          Obrigado pela visita.

  2. Olá Hebert

    configuração executada, porem quando coloco o “.” aparece os atributos “código, nome” etc..

    mas gostaria que aparecesse o salvar, excluir, editar e atualizar e que estão no meu bean,

    mas não aparece, estou utilizando o eclipse juno.

    poderia me auxiliar.

    grato.

    • Leonardo, boa tarde.

      Você instalou o JBoss tools para a versão do seu eclipse?

      Se não instale, que talvez ele possa resolver o seu problema.

      Obrigado pela visita.

      • Olá Hebert

        obrigado pela resposta….

        sim esta instalado….

        estou tendo o problema tanto no Juno quanto no Kepler…

        não sei mais o que fazer….criei o mesmo projeto no NetBeans e funciona perfeitamente

        Grato.

        • Leonardo, boa noite.

          Quando eu algo parecido com o seu, era por que haviam arquivos danificados no workspace.

          Faz o seguinte, baixe um eclipse novo, aponte para um workspace novo, baixe o JBoss Tools e depois crie um projeto de exemplo de JSF e teste o autocomplete.

          Note que após baixar o JBoss Tools você pode criar um new Dynamic Web Project e nele escolher JSF Facete.

          Obrigado pela visita.

  3. Estou tendo dificuldade em implementar meu primeiro converter. Recebi o erro abaixo, ao que parece está sendo passado apenas o id do objeto converter.

    Caused by: java.lang.IllegalArgumentException: Cannot convert 1 of type class model.Permissoes to interface java.util.List

Leave a Comment