Skip to content

Generic Entity Converter for JSF / Spring / JPA

If you’ve come across Seam’s <s:convertEntity> and wondered why isn’t one there for JSF, here you go:

Before using this, you should’ve designed your domain model to extend a Base Class (do it, it’s a good practice). In my case, I have BaseIdentityEntity which has an @Id, @Version properties

import java.io.Serializable;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;

import xxx.model.BaseIdentityEntity;

/**
* Generic Entity Converter for any Entity that extends BaseIdentityEntity
*
*/
@Service("entityConverter")
public class EntityConverter implements Converter, Serializable {
	static Logger log = Logger.getLogger(EntityConverter.class);
	private static final long serialVersionUID = -5137676309479323480L;

	@PersistenceContext
	protected EntityManager entityManager;

	@SuppressWarnings("unchecked")
	public Object getAsObject(FacesContext facesContext, UIComponent component,
			String value) throws ConverterException {
		BaseIdentityEntity entity;
		if (value == null) {
			entity = null;
		} else {
			Integer id = new Integer(value);
			entity = (BaseIdentityEntity) entityManager.find(getClazz(
					facesContext, component), id);
			if (entity == null) {
				log.debug("There is no entity with id:  " + id);
				//throw new IllegalArgumentException("There is no entity with id:  " + id);
			}
		}
		return entity;
	}

	public String getAsString(FacesContext facesContext, UIComponent component,
			Object value) throws ConverterException {
		if (value != null && !(value instanceof BaseIdentityEntity)) {
			throw new IllegalArgumentException(
					"This converter only handles instances of BaseIdentityEntity");
		}
		if (value == null) {
			return "";
		}
		if (value instanceof String) {
			return (String) value;
		}
		BaseIdentityEntity entity = (BaseIdentityEntity) value;
		return entity.getId() == null ? "" : entity.getId().toString();
	}

	// Gets the class corresponding to the context in jsf page
	@SuppressWarnings("unchecked")
	private Class getClazz(FacesContext facesContext, UIComponent component) {
		return component.getValueExpression("value").getType(facesContext.getELContext());
	}

}

You don’t have to add any configuration in the taglibs since Spring’s @Service tag makes the converter a managed bean and you can reference it directly in jsf.

Usage: (Using JSF tomahawk here, but works for any jsf component library)

<h:selectOneMenu value="#{mycontroller.foo}" converter="#{enumConverter}">
	<h:selectItems value="#{mycontroller.foos}" var="element"
	itemLabel="#{element}" itemValue="#{element}" />
</h:selectOneMenu>
[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

2 Comments

  1. Rusty Wright wrote:

    In getAsString() how can the value argument ever be a string? Your first if statement requires it to be BaseIdentityEntity. For me, the code would be clearer if it was along the lines of

    if (value == null) return “”;
    if (value instanceof String) return (String) value;
    if (value instanceof BaseIdentityEntity) {
    BaseIdentityEntity entity = (BaseIdentityEntity) value;
    return entity.getId() == null ? “” : entity.getId().toString();
    }
    throw new IllegalArgumentException(“This converter only handles instances of BaseIdentityEntity”);

    Tuesday, April 28, 2009 at 6:21 pm | Permalink
  2. Rusty Wright wrote:

    Oops; the string argument to IllegalArgumentException needs to include String in addition to BaseIdentityEntity.

    Tuesday, April 28, 2009 at 6:23 pm | Permalink

Post a Comment

Your email is never published nor shared. Required fields are marked *
*
*