History | Log In     View a printable version of the current page.  
Issue Details (XML | Word | Printable)

Key: APF-986
Type: New Feature New Feature
Status: Open Open
Priority: Major Major
Assignee: Matt Raible
Reporter: René Günther
Votes: 0
Watchers: 0
Operations

If you were logged in you would be able to see more operations.
AppFuse

Use JSF SelectItems with persistent objects

Created: 18/Dec/07 06:47 AM   Updated: 18/Dec/07 06:49 AM
Component/s: Web - JSF
Affects Version/s: None
Fix Version/s: None

Environment: basic jsf, hibernate


 Description  « Hide
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>



 All   Comments   Change History   FishEye      Sort Order:
René Günther - 18/Dec/07 06:49 AM
I forgot LabelValueGeneric

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>&lt;html:options&gt;</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();
}
}