JSF: Converter and Bean AutoComplete

JSF: Converter and AutoComplete Bean

Hello, how are you?

Today we will be talking about JSF Converters (a Converter is used in select tags – the famous “ComboBox” – and others) and Eclipse Bean AutoComplete.

Ps.: I will use the term ComboBox (in respect to other technologies – most of it Desktop – like Delphi), that named this component like that. But in web applications we do not use this kind of name.

We need to setup our applications first. I will be quick about some setup configurations and very meticulous about others configurations.

You will need to download a JSF implementation and a JSTL library. You may find them here Mojarra JSF and here JSTL. We already covered this subject (download the jar files) in this post Creating a WebServer, and covered also how to create a JSF application in a post named: JSF – Hello World, Auto Complete.

First, we must download the needed libraries (Mojarra JSF and JSTL). When you finish downloading the files, copy the jar files into the WEB-INF folder. (We did these steps of copying the jar files in the post Creating a WebServer and JSF – Hello World, Auto Complete).

Create a new Dynamic Web Project with the configurations just like in this image (I am using the most recent Eclipse/Tomcat version). Click on the Next button until you find this screen. Select the option “Disable Library Configuration” and click in the “Finish” button.

Let us add the libraries do the Build Path. Click in the Project > Properties. Then click on the Build Path menu, and the “Add Jars” button.

Select in the opened window the files “*.jar” that you will find in the WEB-INF/lib folder. Push the Ok button then close the properties window.

We have to edit the web.xml file (If the Eclipse did not create one web.xml for you, you just have to create the file in the WEB-INF folder and put the following text).

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

Let us create a welcome page just to check if our application is configured correctly. Create a file named index.xhtml inside the WebContent folder. Copy the code bellow into the created file (you can override if there is any code inside there).

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

Start your application using the Tomcat server (if you do not know how to do it, check it here Creating a WebServer). Type this address in your web browser http://localhost:8080/PostJSF/. The index page will be displayed. If any error occurs it is better to you to start over again.

Maybe you will be asking: “What is a Converter? How we can use it?” Let us create a simple sample where we select a user in the first screen and show his name in the next screen. An error will happen…

Create a Java class named User in a package named “com”. This class will look like the code bellow:

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

Let us create a class to manage the request (UserMB); this class will have a User attribute and will show the server date in the other screen.

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

Once the managed bean it is invoked, we will create a map and insert some User objects inside it. These Users could be retrieved from a database.

Let us update our index.xhtml to look like the code bellow. We will be adding a select component with a list of the users coming from our managed bean.

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

Let us create a file named show.xhtml that will display the selected user name.

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

It is an obvious code. You only a select a user name in one page and show his name on the other page with the server date.

Let us run the application to see the result?

Look at your Eclipse console, there is an error message there: “severity=(ERROR 2), summary=(Conversion Error setting value for ‘null Converter’. ), detail=(Conversion Error setting value for ‘null Converter’. )”.

We need to get the selected value and convert it into a User object. After this conversion the JSF will “accept” the selection as a User Object. To create this converter, we will create a Java class that implements the Converter interface – this interfaces has two abstract methods.

Our converter will have the @FacesConverter annotation that the servers will use to locate it when the server starts up. The server will read the class as a Converter and make it available to our view (xhtml pages).

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

And we will edit our index.xhtml one last time. We must “tell” the select tag that it must use the Converter that we created.

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

Let us run our application again and see what will happen?

Notice that in our code we do a search in the Users Map (UserMB), if necessary, we could use some Injected class in the UserMB to search in the database. Be aware of: A Converter will not do a resource injection, even if you use any kind of annotation. e.g.: @EJB. That is the reason that we invoke the Managed Bean and then, we find our User. You could use any resource inside the Managed Bean to search for the user. e.g.: database, file, etc.

A Converter is needed when we want to use an object through a method (like a set) originated from a select (ComboBox) or any other object that allows you to choose from a list of objects. The UserMB setUser is called and the Converter starts to work, through the “getAsObject” method – that having the object ID coming from the select – uses it to get the real object from the map.

How to activate the Eclipse Auto Complete when we talk about Java classes? The Auto Complete will work in classes that are managed by the JSF e.g. ManagedBean, Bundle, etc. You could notice already that our tags already have the auto complete working. (If you did not notice yet, just go to any xhtml file type “<h:” and press ctrl + space bar).

To activate the Auto Complete to java classes – e.g. when you write “#{userMB.user.}”, a list of methods and options will be displayed – we will need to edit our faces-config.xml and the UserMB.

In the UserMB we will just remove the “@ManagedBean” and “@RequestScoped” annotations. Our new class code will be:

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

We just need to edit the faces-config.xml. We will need to add the Managed Bean into the xml file; to do this just click in the tab ManagedBean.

Select the “request” option and then click the button “add”. Type UserMB (our class will be displayed) select it and click in the finish button and save all your file updates.

Open the show.xhtml file, and inside the EL “#{userMB.user}” type a . (dot) and after the dot press ctrl + space bar and you will see the “magic”.

Do not think that by using xml instead annotations that you will be receding. Some Design Patterns says that using annotation is intrusive, and you are breaking the class cohesion. The class does not have to know the database behavior or configurations. One of the reasons that Spring/Hibernate/JPA/JSF allows the xml configurations is this kind of approach. The only thing that we did it was to inform the Managed Bean that we will use.

You will be able to edit your “faces-config.xml” through the interface that the Eclipse allows us to use.

A last topic about our subject is that your Project Facets must be checked as JSF. In this post we see how to change a Project Facets: JSF – Hello World, Auto Complete.

I hope this post might help you.

If you have any question, just post it.

See you soon.

6 thoughts on “JSF: Converter and Bean AutoComplete

  1. Dear friend
    I’m beginner in Jsf and Primefaces. I have a problem to using p:selectOneMenu tag in NetBens IDE. I followed your post step by step but I find a message in browser like this “org.primefaces.component.selectonemenu.SelectOneMenuRenderer.getSelectItems(Ljavax/faces/context/FacesContext;Ljavax/faces/component/UIInput;)Ljava/util/List;” .
    here is my code what i used. I want to change interface language from this combobox.

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

    @FacesConverter(value=”languageConverter”)
    public class LanguageConverter implements Converter {

    @Override
    public Object getAsObject(FacesContext arg0, UIComponent arg1, String key) {
    FacesContext context = FacesContext.getCurrentInstance();
    LanguageManager languageManager = (LanguageManager) context.getELContext().getELResolver().getValue(context.getELContext(), null, “languageManager”);

    return languageManager.setLngSelected(key);
    }

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

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

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

    @ManagedBean(name = “languageManager”)
    @RequestScoped
    public class LanguageManager {

    private Map alLanguages;
    private Language lngSelected;

    public LanguageManager() {
    alLanguages = new HashMap();
    alLanguages.put(“English”,new Language(“English”, “english.gif”));
    alLanguages.put(“Farsi”,new Language(“Farsi”, “farsi.gif”));
    alLanguages.put(“French”,new Language(“French”, “france.gif”));
    }

    public Language getLngSelected() {
    return lngSelected;
    }

    public Language setLngSelected(String strSelected) {
    return this.lngSelected = (Language) alLanguages.get(lngSelected);
    }

    public List getAlLanguages() {
    return new ArrayList(alLanguages.values());
    }
    }

    import javax.faces.bean.ManagedBean;
    import javax.faces.bean.SessionScoped;

    @ManagedBean
    @SessionScoped
    public class Language{

    private String strLangName;
    private String strLangImage;

    public Language(String strLangName, String strLangImage) {
    this.strLangName = strLangName;
    this.strLangImage = strLangImage;
    }

    public String getStrLangImage() {
    return strLangImage;
    }

    public void setStrLangImage(String strLangImage) {
    this.strLangImage = strLangImage;
    }

    public String getStrLangName() {
    return strLangName;
    }

    public void setStrLangName(String strLangName) {
    this.strLangName = strLangName;
    }
    }

    I’ll appreciate if you have any suggestion.

  2. Here is my html snippet code:

    p:selectOneMenu value=”#{languageManager.lngSelected}” converter=”languageConverter” var=”lang” >

    f:selectItems value=”#{languageManager.alLanguages}” var=”lng”
    itemLabel=”#{language.strLangName}” itemValue=”#{language.strLangName}”

    /p:selectOneMenu>

    • Hello Mori,
      You need to understand JSF better. I think you could read this book: Core JavaServer Faces 3rd – Cay Horstmann, David Geary
      I am saying this because, this class Language do not need to be a ManagedBean. It could be a POJO (plain old java class).
      You selectOne is using the method value=”#{languageManager.lngSelected}” but your setLngSelected is receiving a String instead of a Language.
      Why are all your managedBeans as SessionScoped? The Map alLanguages could be Map.
      There are others concepts you could change in your code but is too far from this post subject.

Leave a Comment