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>
2 Comments
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”);
Oops; the string argument to IllegalArgumentException needs to include String in addition to BaseIdentityEntity.
Post a Comment