JSF converter for SelectOneMenu

The main JSF feature (or, at least, the one I like the most) is the ease to link controller bean attributes to xhtml view. However there’s an inherent important limitation: in the HTTP standard keys and values always will be strings, because they are sent that way. Of course you could serialize an object to base64, but a barbaric thing like that should be avoided in almost any circumstance.

Then how can we link a HTTP control to an object? For that, JSF provides converters. Well, it will allow you to program them, of course. Neither PrimeFaces, my library of choice, includes these converters. Thus, I’ve programmed a simple one for SelectOneMenu, the dropdown menus in the like of a combobox. I’ll leave it here for my own reference, and for anyone that could use it.

/**
 * The Class SelectOneMenuConverter.
 */
@FacesConverter("selectOneMenuConverter")
public class SelectOneMenuConverter implements Converter {

	@Override
	public Object getAsObject(final FacesContext arg0, final UIComponent arg1, final String objectString) {
		if (objectString == null) {
			return null;
		}

		return fromSelect(arg1, objectString);
	}

	/**
	 * Serialize.
	 *
	 * @param object
	 *            the object
	 * @return the string
	 */
	private String serialize(final Object object) {
		if (object == null) {
			return null;
		}
		return object.getClass() + "@" + object.hashCode();
	}

	/**
	 * From select.
	 *
	 * @param currentcomponent
	 *            the currentcomponent
	 * @param objectString
	 *            the object string
	 * @return the object
	 */
	private Object fromSelect(final UIComponent currentcomponent, final String objectString) {

		if (currentcomponent.getClass() == UISelectItem.class) {
			final UISelectItem item = (UISelectItem) currentcomponent;
			final Object value = item.getValue();
			if (objectString.equals(serialize(value))) {
				return value;
			}
		}

		if (currentcomponent.getClass() == UISelectItems.class) {
			final UISelectItems items = (UISelectItems) currentcomponent;
			final List<Object> elements = (List<Object>) items.getValue();
			for (final Object element : elements) {
				if (objectString.equals(serialize(element))) {
					return element;
				}
			}
		}


		if (!currentcomponent.getChildren().isEmpty()) {
			for (final UIComponent component : currentcomponent.getChildren()) {
				final Object result = fromSelect(component, objectString);
				if (result != null) {
					return result;
				}
			}
		}
		return null;
	}

	@Override
	public String getAsString(final FacesContext arg0, final UIComponent arg1, final Object object) {
		return serialize(object);
	}

}

Basically, it converts any objects in a coded string with the class name and its hash. When you want to recover it, it access the collection linked to our dropdown menu value to look up the object so it can return it. It relies on the proper implementation of the hashCode method, and it requires it to return different values for different objects, but it’s a nice and quick way to do it, and will work in almost all circumstances. Using it is as easy as:

<p:selectOneMenu id="utiSelector" converter="selectOneMenuConverter" value="#{myBean.myObject}">	
        <f:selectItem itemValue="#{null}" noSelectionOption="true" />
	<f:selectItems value="#{myBean.objectList}" var="object" itemValue="#{object}" itemLabel="#{objeto.label}">
</p:selectOneMenu>

Something I usually do in the DTOs or entities is to make the hashcode to be the key, or the key’s hashcode if it’s compound or non numeric. But that’s another story.

Leave a Reply

Your e-mail address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.