Wednesday, February 15, 2012

Custom converter class
(Seam, JSF, Richfaces)

I'm going to show you how to write a custom converter class to let users to select and pass an Object using a JSF's <h:selectOneMenu/> component.
Since this component is finally rendered as a HTML 'select' element, it can't hold or submit Objects. So you need a converter class to convert the submitted value to matching Object type.
I am using following simple class as the seam component. Seam name of it is 'test'. (Instead of the seam component you can use a JSF managed bean also)
The combo box I'm going to use is filled with 'datesSelectList'.
The selected date is going to be set to 'selectedDate' variable.

import java.util.*;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.*;
import javax.faces.model.SelectItem;

@Name("test")
public class Test {
  List<SelectItem> datesSelectList = new ArrayList<SelectItem>();
  Date selectedDate;

  @Create
  public void init() {
    buildDatesSelectList();
  }

  public List<SelectItem> getDatesSelectList(){
    return datesSelectList;
  }

  public void buildDatesSelectList(){
    Date baseDate = new Date();
    Date date1 = new Date(baseDate.getTime());
    Date date2 = new Date(baseDate.getTime() + 5000);
    Date date3 = new Date(baseDate.getTime() + 10000);
    datesSelectList.add(new SelectItem(date1, "Date 1"));
    datesSelectList.add(new SelectItem(date2, "Date 2"));
    datesSelectList.add(new SelectItem(date3, "Date 3"));
  }

  public Date getSelectedDate() {
    return selectedDate;
  }

  public void setSelectedDate(Date selectedDate) {
    System.out.println("Date Selected : " + selectedDate);
    this.selectedDate = selectedDate;
  }
}

Your page would be as below.
<h:form>
  <h:selectOneMenu value="#{test.selectedDate}" id="sList">
    <s:selectItems value="#{test.datesSelectList}" var="_date"
       itemValue="#{_date.value}" label="#{_date.label}" />
    <f:converter converterId="myDateConverter"></f:converter>
  </h:selectOneMenu>
  <rich:message for="sList"/><br/>
  <a4j:commandButton value="submit"/>
</h:form>

Now it is time to write our converter class. To do that I will have to implement the interface 'javax.faces.convert.Converter'.
In this example the user selects a Date from combo box, and that date value should be set to the 'selectedDate' variable through 'setSelectedDate()' method.
So our converter should capture the label of the selected date('Date 1', 'Date 2' or 'Date 3') and find the relevant Date object.

package inova.erp.jbpm.temp;
import java.util.*;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.model.SelectItem;
import org.jboss.seam.Component;


public class DateConverter implements Converter {
  
  public Object getAsObject(FacesContext context, UIComponent uiComp, String dateString) {
    System.out.println("dateString = " + dateString);
    Object obj = Component.getInstance("test");
    Test test = (Test)obj;
    List<SelectItem> selectItems = test.getDatesSelectList();
    for(SelectItem sItem : selectItems) {
      if(sItem.getLabel().equals(dateString)) {
        return (Date)sItem.getValue();//Finding matching Date
         object for selected label (dateString) 
      }
    }
    return null;
  }
  public String getAsString(FacesContext context, UIComponent uiComp, Object dateObj) {
    return null;
  }
}

Now our work is almost ok. The final part is we have to introduce our new "DateConverter" class as a converter. We can do it in 'faces-config.xml' as below.
<converter>
  <converter-id>myDateConverter</converter-id>
  <converter-class>  
    inova.erp.jbpm.temp.DateConverter
  </converter-class>
</converter>

Now build and run the page. Then select a value from combo box and press 'Submit' button.
You will see the output similar to 'Date Selected : Tue Feb 14 19:51:24 IST 2012' in your console.
It indicates that you have successfully selected a Date Object using your combo box.
Now remove the line
  '<f:converter converterId="myDateConverter"></f:converter>'
 and try again. You will get an error at submission.

Note Followings:

  • You can add the "converter" attribute to the <h:selectOneMenu/> and remove the <f:converter/> component as below.
    <h:form>
      <h:selectOneMenu value="#{test.selectedDate}" id="sList" converter="myDateConverter">
        <s:selectItems value="#{test.datesSelectList}" var="_date"
           itemValue="#{_date.value}" label="#{_date.label}" />
      </h:selectOneMenu>
      <rich:message for="sList"/><br/>
      <a4j:commandButton value="submit"/>
    </h:form>
  • If you are using seam, you can use the seam annotation '@Converter' together withe '@Name' annotation to define the converter instead editing 'faces-config.xml'.

    import org.jboss.seam.annotations.Name;
    import org.jboss.seam.annotations.faces.Converter;
    import org.jboss.seam.annotations.intercept.BypassInterceptors;
    @Name("myDateConverter")
    @Converter
    @BypassInterceptors
    public class DateConverter implements javax.faces.convert.Converter {

No comments:

Post a Comment