Using f:selectItems with JPA entities
It's a common scenario: you must do a "SELECT e FROM Entity e" with JPA and pass it to a <h:selectOneMenu> or a <h:selectManyList>. Unfortunately, if you google it, you will find a lot of strange solutions.
I've tested a simple solution on JavaEE 6. On my managed bean, I can define a property like this:
... public class MyBean { ... @PersistenceContext private EntityManager em; public Converter getConverter() { return new Converter() { @Override public Object getAsObject( FacesContext fc, UIComponent uic, String string) { return (string == null) ? null : em.find(MyEntity.class, Long.parseLong(string)); } @Override public String getAsString( FacesContext fc, UIComponent uic, Object o) { return (o == null) ? null : Long.toString(((MyEntity) o).getId()); } }; } }
According to JSF specification, only managed beans can be injected. This is why I declared it as an inner class.
This way, the converter allows you to work only with entities, instead of manually storing IDs on the managed bean. This means the page can bind to this property when a conversion is needed:
<h:selectOneMenu value="#{myBean.myEntitySelection}"> <f:selectItems value="#{myBean.myEntityList}"/> <f:converter binding="#{myBean.converter}"/> </h:selectOneMenu>
One last step: your Entity must have an working "equals" method. If you forget this, you will receive the message "Validation Exception: Value is invalid".
Usually, a boilerplate, like this one generated by NetBeans will suffice:
@Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final MyEntity other = (MyEntity) obj; if (this.id != other.id && (this.id == null || !this.id.equals(other.id))) { return false; } return true; }
Works like a charm on JSF 2, but I haven't tested on JSF 1.2.
BTW, this solution can be refactored to became a more generic: create a base entity class that declares a "getId" method returning Serializable. Then, the converter can be a class receiving an entity manager and the persistent class.