Wednesday, March 11, 2009

Use OGNL expressions to fill your SelectOneMenu

JSF selectOneMenu component is loaded with "selectItems" tag. Like; 
<h:selectOneMenu id="som_city" value="#{}">
<t:selectItems value="#{cityService.getCities}" itemLabel="#{}" itemValue="#{val.this}" var="val" />
With the help of some converter we are able to list cities in the combo with the expression "#{cityService.getCities}". But often what we realy want to do is list the cities of certain country which is perhaps choosen from another combo. What we need is another expression like "#{cityService.getCities(someCountry)}". 
To achive this I have overriden the myfaces UISelectItems and gave it the power of Ognl expressions:
import java.util.AbstractMap;
import java.util.HashSet;
import java.util.Set;

import javax.faces.context.FacesContext;
import javax.faces.el.ValueBinding;

import ognl.Ognl;
import ognl.OgnlException;

import org.apache.myfaces.custom.selectitems.UISelectItems;

public class UISelectSmarterItems extends UISelectItems {

private String expString;

public String getExpString() {
if (expString != null)
return expString;

ValueBinding vb = getValueBinding("expString");
String v = vb != null ? (String) vb.getValue(getFacesContext()) : null;
return v;

public void setExpString(String expString) {
this.expString = expString;

public Object getValue() {
String str = getExpString();
if (str != null && str.length() > 0) {

return super.getValue();

private Object evaluateExpression(String aExp) {
try {
return Ognl.getValue(aExp, new FacesEvaluationContext());
catch (OgnlException e) {
throw new RuntimeException(aExp);

private final class FacesEvaluationContext extends AbstractMap {

public Object get(Object key) {
return resolveVariable(key);

private Object resolveVariable(Object key) {
return getFacesContext().getApplication().createValueBinding("#{" + key + "}").getValue(getFacesContext());

public Set entrySet() {
return new HashSet();

public Object saveState(FacesContext context) {
Object values[] = new Object[2];
values[0] = super.saveState(context);
values[1] = expString;
return ((Object) (values));

public void restoreState(FacesContext context, Object state) {
Object values[] = (Object[]) state;
super.restoreState(context, values[0]);
expString = (String) values[1];

What I did is add expString property and give it the power of Ognl expression. In the end we are able write this;
<injsf:selectItems expString="cityService.getCities(someCity)"
var="val" itemLabel="#{}" itemValue="#{val.this}"

No comments:

Post a Comment