Home > JSF, Java > JSF value binding

JSF value binding

Today i will explain three types of value binding:

  • “direct” value binding (one setter / getter for each value)
  • “list based” value binding (one setter / getter for a list of values)
  • “map based” value binding (one setter / getter for a map of values)

Direct value binding

This is the classic usage of value binding in jsf, the following facelets-snippet is self-explanatory:

<h:inputText value="#{bean.foo}"/>
<h:inputText value="#{bean.bar}"/>

Our bean have a setter and a getter for foo and bar:

class Bean {
 private String foo, bar;
 public String getFoo() ...
 public void setFoo(String) ...
 public String getBar() ...  
 public void setBar(String) ...
}

List based value binding

I use this to avoid setter and getter for similar values/properties, i.e.

<h:inputText value="#{bean.product[0]}"/>
<h:inputText value="#{bean.product[1]}"/>
<h:inputText value="#{bean.product[2]}"/>
...

With the “classic” value binding i have to write a lot of getter/setter (product0, product1, product2,…). But with list based value binding its much easier.


class Bean {
 private static final int MAX_NUMBER_OF_PRODUCTS = 5;
 private final Product[] products = new Product[MAX_NUMBER_OF_PRODUCTS];
 public Bean () {
 for (int i = 0; i < MAX_NUMBER_OF_PRODUCTS; i++) {
 products[i] = null;
 }
 }
 public List<Product> getProduct() {
 return Arrays.asList(Product);
 }
}

The initialization of the internal array/list is necessary for correct working! During runtime jsf will access each value via index (0, 1, 2, …), a uninitialized list will throw a IndexOutOfBounds Exception.

Map based value binding

I used this type of value binding in a generic “CRUD list” view to implement filtering in a rich:dataTable. I want  a selectbox for each “filterable” column:


<rich:column>
 <f:facet name="header">
 <h:selectOneMenu value="#{bean.filterValue['foo']}">
 <f:selectItems value="#{bean.filterValues['foo']}" />
 </h:selectOneMenu>
 </f:facet>
 ...
</rich:column>

<rich:column>
 <f:facet name="header">
 <h:selectOneMenu value="#{bean.filterValue['bar']}">
 <f:selectItems value="#{bean.filterValues['bar']}" />
 </h:selectOneMenu>
 </f:facet>
 ...
 </rich:column>

To get this to work we need a “customized” map implementation:

class ArrayMap<K, T> extends HashMap<K, T> {
 private static final long serialVersionUID = -5766406097936988242L;
 @Override
 public T get(final Object theKey) {
 if (!containsKey(theKey)) {
 // to avoid typos in the ui we throw a exception if a "unknown" value-name is used
 throw new IllegalArgumentException(String.format("The given value-name '%s' is not available", theKey));
 }
 return super.get(theKey);
 }
 public void set(final K key, final T value) {
 super.put(key, value);
 }
 }

This ArrayMap have a getter and a setter (the “normal” Map have only get and put), for jsf value binding we need a set and a get.

Here is the final filter – bean:


class FilterBean {

/**
 * Contain all available filter-values for each supported filter-name.
 */
 private final Map<String, List<SelectItem>> filterValues = new ArrayMap<String, List<SelectItem>>();

 /**
 * Contain the current filter-value for each supported filter-name.
 */
 private final ArrayMap<String, Object> filterValue = new ArrayMap<String, Object>();

/*
 * Constructor.
 */
public FilterBean() {
 initFilterValue();
 }

/**
 * @return a map of lists with {@link SelectItem}s
 */
 public Map<String, List<SelectItem>> getFilterValues() {
 return filterValues;
 }

 /**
 * @return the map of filter values
 */
 public ArrayMap<String, Object> getFilterValue() {
 return filterValue;
 }

/**
 * Prepare <tt>filterValue</tt>, add all supported filter-names to the list.
 */
 private void initFilterValue() {
 filterValue.set("foo", null);
 filterValue.set("bar", null);
}

/**
 * Prepare <tt>filterValues</tt>, the given list contains all rows for the datatable. Each filter-selectbox must
 * show a unique list of available filter-values (per supported filter column).
 */
public synchronized void initFilterValues(final List<T> theInitialFilterList) {
 filterValues.clear();
 filterValues.put("foo", getFilterSelectItemsFoo(theInitialFilterList));
 filterValues.put("bar", getFilterSelectItemsBar(theInitialFilterList));}
}

}

The method initFilterValues(final List<T>) will be triggered from a external bean. Then the filter-bean  can create a list of SelectItems for each filter-column.

If the User select a value from such a filter-list the value binding will call our ArrayMap.set method.

Try it :D

Categories: JSF, Java Tags: ,
  1. No comments yet.
  1. No trackbacks yet.
You must be logged in to post a comment.