In a recent JSF project I found some difficulties how to use select items with persistent objects. I dont know where to put it, here or in the wiki .. so I just try here .
I want to share a solution which is based on
http://wiki.jboss.org/wiki/Wiki.jsp?page=SelectItems.
Just add the interfaces and classes and you should be able to use select menus based on User objects:
package com.innflow.bj2.webapp.util.si;
import java.io.Serializable;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.faces.convert.Converter;
/**
*
* @author Rene Guenther
rene.guenther@innflow.com
*
* @param <T>
*/
public interface BaseSIIntf<T> extends Serializable {
public Map<String, T> getSelectItems(Locale locale);
public Map<String, T> getSelectItems();
public List<T> getAllObjects();
public Converter getConverter();
}
package com.innflow.bj2.webapp.util.si;
import java.text.Collator;
import java.util.Comparator;
import java.util.Locale;
import com.innflow.bj2.model.LabelValueGeneric;
import com.innflow.bj2.webapp.action.BasePage;
/**
*
* @author Rene Guenther
rene.guenther@innflow.com
*
*/
public class BaseSI extends BasePage{
/**
* Class to compare LabelValues using their labels with locale-sensitive
* behaviour.
*/
public class LabelValueComparator implements Comparator<Object> {
private Comparator<Object> c;
/**
* Creates a new LabelValueComparator object.
*
* @param locale
* The Locale used for localized String comparison.
*/
public LabelValueComparator(Locale locale) {
c = Collator.getInstance(locale);
}
/**
* Compares the localized labels of two LabelValues.
*
* @param o1
* The first LabelValue to compare.
* @param o2
* The second LabelValue to compare.
*
* @return The value returned by comparing the localized labels.
*/
public final int compare(Object o1, Object o2) {
LabelValueGeneric lhs = (LabelValueGeneric) o1;
LabelValueGeneric rhs = (LabelValueGeneric) o2;
return c.compare(lhs.getLabel(), rhs.getLabel());
}
}
}
package com.innflow.bj2.webapp.util.si;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.annotation.Resource;
import javax.faces.convert.Converter;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import com.innflow.bj2.model.LabelValueGeneric;
import com.innflow.bj2.model.User;
import com.innflow.bj2.service.UserManager;
import com.innflow.bj2.webapp.jsf.ReferenceConverter;
/**
* @author Rene Guenther
rene.guenther@innflow.com
*/
@Controller("userSI")
@Scope("request")
public class UserSI extends BaseSI implements BaseSIIntf<User> {
/**
*
*/
private static final long serialVersionUID = 5816369678066099896L;
private UserManager manager;
private Map<String, User> selectItems;
private List<User> allObjects;
@Resource(name = "userManager")
public void setManager(UserManager manager) {
this.manager = manager;
}
public Map<String, User> getSelectItems() {
return getSelectItems(getRequest().getLocale());
}
public Map<String, User> getSelectItems(Locale locale) {
if (this.selectItems == null) {
allObjects = manager.getUsers(null);
List<LabelValueGeneric<User>> objects = new ArrayList<LabelValueGeneric<User>>();
for (User user : allObjects) {
final String label = user.getUsername() + " ("
+ user.getFullName() + ")";
objects.add(new LabelValueGeneric<User>(label, user));
}
if (null == locale)
Collections.sort(objects);
else
Collections.sort(objects, new LabelValueComparator(locale));
Map<String, User> options = new LinkedHashMap<String, User>();
for (LabelValueGeneric<User> lv : objects) {
options.put(lv.getLabel(), lv.getValue());
}
this.selectItems = options;
}
return this.selectItems;
}
public List<User> getAllObjects() {
if (allObjects == null) {
allObjects = manager.getUsers(null);
}
return allObjects;
}
public Converter getConverter() {
return new ReferenceConverter<User>(getAllObjects());
}
}
package com.innflow.bj2.webapp.jsf;
import java.io.Serializable;
import java.util.List;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
/**
*
*
* <p>
* Based on
http://wiki.jboss.org/wiki/Wiki.jsp?page=SelectItems
*
* @param <T>
*/
public class ReferenceConverter<T> implements Serializable, Converter {
/**
*
*/
private static final long serialVersionUID = -1100627491163130596L;
private static final String EMPTY = "__EMPTY__";
private List<T> values;
public ReferenceConverter(List<T> vals) {
this.values = vals;
}
public String getAsString(FacesContext facesContext, UIComponent component,
Object obj) {
if (obj == null)
return EMPTY;
if ("-1".equals(obj))
return EMPTY;
String val = String.valueOf(obj.hashCode());
return val;
}
public Object getAsObject(FacesContext facesContext, UIComponent component,
String str) throws ConverterException {
if (str == null || str.length() == 0 || EMPTY.equals(str)) {
return null;
}
int hash = Integer.valueOf(str).intValue();
for (T val : values) {
if (val != null && val.hashCode() == hash) {
return val;
}
}
return null;
}
}
Example usage on xhtml page:
<h:outputLabel for="refUser" styleClass="desc"
value="#{text['user.user']}" />
<t:message for="refUser" styleClass="fieldError" />
<t:selectOneMenu value="#{userForm.refUser}" id="refUser"
styleClass="select" disabled="#{!userForm.roleAdmin}" converter="#{userSI.converter}">
<f:selectItems value="#{userSI.selectItems}" />
</t:selectOneMenu>
package com.innflow.bj2.model;
import java.io.Serializable;
import java.util.Comparator;
/**
* A simple JavaBean to represent label-value pairs. This is most commonly used
* when constructing user interface elements which have a label to be displayed
* to the user, and a corresponding value to be returned to the server. One
* example is the <code><html:options></code> tag.
*
* <p>
* Note: this class has a natural ordering that is inconsistent with equals.
* <p>
* This class supports values of generic type (labels are still strings
*
* @see org.apache.struts.util.LabelValueBean
*/
public class LabelValueGeneric<S> implements Comparable<LabelValueGeneric<S>>, Serializable {
private static final long serialVersionUID = 3689355407466181430L;
/**
* Comparator that can be used for a case insensitive sort of
* <code>LabelValueGeneric</code> objects.
*/
public static final Comparator<Object> CASE_INSENSITIVE_ORDER = new Comparator<Object>() {
@SuppressWarnings("unchecked")
public int compare(Object o1, Object o2) {
String label1 = ((LabelValueGeneric) o1).getLabel();
String label2 = ((LabelValueGeneric) o2).getLabel();
return label1.compareToIgnoreCase(label2);
}
};
// ----------------------------------------------------------- Constructors
/**
* Default constructor.
*/
public LabelValueGeneric() {
super();
}
/**
* Construct an instance with the supplied property values.
*
* @param label
* The label to be displayed to the user.
* @param value
* The value to be returned to the server.
*/
public LabelValueGeneric(final String label, final S value) {
this.label = label;
this.value = value;
}
// ------------------------------------------------------------- Properties
/**
* The property which supplies the option label visible to the end user.
*/
private String label;
public String getLabel() {
return this.label;
}
public void setLabel(String label) {
this.label = label;
}
/**
* The property which supplies the value returned to the server.
*/
private S value;
public S getValue() {
return this.value;
}
public void setValue(S value) {
this.value = value;
}
// --------------------------------------------------------- Public Methods
/**
* Compare LabelValueBeans based on the label, because that's the human
* viewable part of the object.
*
* @see Comparable
* @param o
* LabelValue object to compare to
* @return 0 if labels match for compared objects
*/
public int compareTo(LabelValueGeneric<S> o) {
// Implicitly tests for the correct type, throwing
// ClassCastException as required by interface
String otherLabel = o.getLabel();
return this.getLabel().compareTo(otherLabel);
}
/**
* Return a string representation of this object.
*
* @return object as a string
*/
public String toString() {
StringBuffer sb = new StringBuffer("LabelValue[");
sb.append(this.label);
sb.append(", ");
sb.append(this.value.toString());
sb.append("]");
return (sb.toString());
}
/**
* LabelValueBeans are equal if their values are both null or equal.
*
* @see java.lang.Object#equals(java.lang.Object)
* @param obj
* object to compare to
* @return true/false based on whether values match or not
*/
@SuppressWarnings("unchecked")
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof LabelValueGeneric)) {
return false;
}
LabelValueGeneric bean = (LabelValueGeneric) obj;
int nil = (this.getValue() == null) ? 1 : 0;
nil += (bean.getValue() == null) ? 1 : 0;
if (nil == 2) {
return true;
} else if (nil == 1) {
return false;
} else {
return this.getValue().equals(bean.getValue());
}
}
/**
* The hash code is based on the object's value.
*
* @see java.lang.Object#hashCode()
* @return hashCode
*/
public int hashCode() {
return (this.getValue() == null) ? 17 : this.getValue().hashCode();
}
}