On the jsf "create new user" page, I have SelectOneMenu with a custom converter and selectSelectionOption selectItem as follows: (irrelevant code is ommitted)
NewUser.xhtml
<h:form> <h:selectOneMenu value="#{newUserController.user.department}" required="true" converter="departmentConverter"> <f:selectItem itemLabel="Select a department" noSelectionOption="true"/> <f:selectItems value="#{newUserController.departments}" var="dep" itemLabel="#{dep.name}" itemValue="#{dep}"/> </h:selectOneMenu> <p:commandButton action="#{newUserController.saveUser}" value="#{bundle.Save}" ajax="false"/> </h:form>
NewUserController.java
@ManagedBean @ViewScoped public class NewUserController implements Serializable { private static final long serialVersionUID = 10L; @EJB private UserBean userBean; private List<Department> departments; private User user; public NewUserController () { } @PostConstruct public void init(){ user = new User(); departments = userBean.findAllDepartments(); } public User getUser() { return user; } public void setUser(User user) { this.user = user; } public List<Department> getDepartments(){ return departments; } public String saveUser() {
DepartmentConverter.java
@FacesConverter(value="departmentConverter") public class DepartmentConverter extends EntityConverter { public DepartmentConverter(){ super(Department.class); } }
Super converter for all objects
public class EntityConverter<E> implements Converter{ protected Class<E> entityClass; public EntityConverter(Class<E> type) { entityClass = type; } @Override public Object getAsObject(FacesContext facesContext, UIComponent component, String value) { if (value == null || value.length() == 0) { return null; } try { InitialContext ic = new InitialContext(); UserBean ub = (UserBean)ic.lookup("java:global/CompetenceRegister/UserBean"); return ub.find(entityClass, getKey(value)); } catch (NamingException e) { return null; } } Long getKey(String value) { Long key; key = Long.valueOf(value); return key; } String getStringKey(Long value) { StringBuilder sb = new StringBuilder(); sb.append(value); return sb.toString(); } @Override public String getAsString(FacesContext facesContext, UIComponent component, Object object) { if (object == null) { return null; } if (object instanceof AbstractEntity) { AbstractEntity e = (AbstractEntity) object; return getStringKey(e.getId()); } else throw new IllegalArgumentException("object " + object + " is of type " + object.getClass().getName() + "; expected type: " + entityClass.getName()); }
}
However, when I submit the form with the "Select Department" option selected, it sends a shortcut to getAsObject in the converter instead of a null value, which causes the converter to throw an exception in getKey (trying to convert a String containing id to Long). Setting the itemValue attribute of the selectItem element to null is not affected. Elements from the collection work great with the converter. Does anyone have an idea of ββwhat causes this?
Update An interesting thing that I forgot to mention; if I remove the converter attribute from SelectOneMenu, noSelectionAttribute will work as it should, but since the converter does not know by default how to convert my objects, the post will fail when choosing the true department. Could this mean that noSelectionOption = true SUPPOSED sends its label instead, and the converter must somehow handle it?
jsf jsf-2 converter selectonemenu
Rasmus franke
source share