Hello,
I'm coding a generic object converter which will work for non jpa backends (i.e. jca,
jdbc, ...) - similar to the one in
http://www.jboss.com/index.html?module=bb&op=viewtopic&t=122149&a....
But stateless.
The converter is used for selectItems - Here is a sample jsf code to display a country
selectBox (sx:convertObject) :
<h:selectOneMenu id="country"
| value="#{client.adress.country}" styleClass="selectBox">
| <sx:convertObject var="value" asStringEl="value.id"/>
| <s:selectItems value="#{countryManager.allCountries}"
| var="country" label="#{country.libelle}"
| noSelectionLabel="Please Select..." />
| </h:selectOneMenu>
How does it work ?
On render, it applies the el #{value.id} on every object of selectItems (so call
country.getId for every country).
On submit, it applies once more this el on all selectItems objects until retrieving the
selected string value.
Here's my questions :
1. I would lik to use a real EL in asStringEl attribute.
How can I achieve it in a converter ?
I've tried setting asStringEl="#{value.id}", but facelets interprets it
*before* my converter - and I retrieve value "" in my converter.
2. Does this approach appears fine or is there a better one (it's my first Jsf
converter - so quite a newbie...).
Sorry for this long mail and thank you very much for you help.
Here's my converter code :
@Name("com.natixis.sphinx.jsf.component.objectConverter")
| @org.jboss.seam.annotations.jsf.Converter
| @Scope(ScopeType.STATELESS)
| @Install(precedence=Install.FRAMEWORK)
| public class ObjectConverter implements Converter, Serializable {
|
| /** Champ serialVersionUID. */
| private static final long serialVersionUID = -8229857238533003490L;
| private String asStringEl;
| private String var;
|
| public Object getAsObject(FacesContext aFacesContext, UIComponent aComponent,
String aValueAsString) {
| if (aValueAsString == null) {
| return null;
| }
|
| //1. récupération valeurs selectItems
| SelectItemsIterator lIterator = new SelectItemsIterator(aComponent);
|
| //2. recherche du SelectItem correspondant à aValueAsString
| while (lIterator.hasNext()) {
| Object lItem = lIterator.next().getValue();
| String lAsString = convertToString (lItem, aFacesContext);
| if (aValueAsString.equals (lAsString)) {
| return lItem;
| }
| }
| //TODO : should never happen or illegal data.... ou aucune valeur
sélectionnée
| return null;
| }
|
| @SuppressWarnings("unchecked")
| private void restoreInRequest(Object aOld, FacesContext aFacesContext) {
| Map lRequestMap = aFacesContext.getExternalContext().getRequestMap();
| if (aOld == null) {
| lRequestMap.remove(getVar());
| } else {
| lRequestMap.put(getVar(), aOld);
| }
| }
|
| @SuppressWarnings("unchecked")
| private Object storeInRequest(Object aItem, FacesContext aFacesContext) {
| Map lRequestMap = aFacesContext.getExternalContext().getRequestMap();
| return lRequestMap.put(getVar(), aItem);
| }
|
| public String getVar() {
| //valeur attribut var
| return var;
| }
|
| public void setVar (String aVar) {
| var = aVar;
| }
|
| public String getAsStringEl() {
| return "#{"+asStringEl+"}";
| }
|
| public void setAsStringEl(String aValue) {
| asStringEl = aValue;
| }
|
| public String getAsString(FacesContext aFacesContext, UIComponent aComponent,
Object aValue) {
| if (aValue == null) {
| return null;
| }
| return convertToString(aValue, aFacesContext);
| }
|
| private String convertToString (Object aObject, FacesContext aFacesContext) {
| Object lOld = storeInRequest (aObject, aFacesContext);
| try {
| return Interpolator.instance().interpolate(getAsStringEl());
| } finally {
| restoreInRequest (lOld, aFacesContext);
| }
| }
| }
|
Here's the taglib.xml file :
| <?xml version="1.0"?>
| <!DOCTYPE facelet-taglib PUBLIC
| "-//Sun Microsystems, Inc.//DTD Facelet Taglib 1.0//EN"
| "facelet-taglib_1_0.dtd">
|
| <facelet-taglib>
| <
namespace>http://test.com/sphinx-jsf/taglib</namespace>
| <tag>
| <tag-name>convertObject</tag-name>
| <converter>
|
<converter-id>com.natixis.sphinx.jsf.component.objectConverter</converter-id>
| </converter>
| </tag>
| </facelet-taglib>
|
An utility file (from myfaces 1.1.5) :
| package com.natixis.sphinx.jsf.component;
|
| import java.util.*;
|
| import javax.faces.component.UIComponent;
| import javax.faces.component.UISelectItem;
| import javax.faces.component.UISelectItems;
| import javax.faces.component.UIViewRoot;
| import javax.faces.el.ValueBinding;
| import javax.faces.model.SelectItem;
|
|
| /**
| * <p>Cette classe est issue de MyFaces 1.1.5.</p>
| *
| * <p>Elle nous permet de récupérer simplement les valeur d'un composant
selectItems
| * à partir du composant parent (i.e. selectOneMenu par exemple).</p>
| */
| class SelectItemsIterator implements Iterator<SelectItem>
| {
| private final Iterator _childs;
| private Iterator _nestedItems;
| private Object _nextItem;
| private String _collectionLabel;
| private UISelectItems _currentUISelectItems;
|
| public SelectItemsIterator(UIComponent selectItemsParent)
| {
| _childs = selectItemsParent.getChildren().iterator();
| }
|
| @SuppressWarnings("unchecked")
| public boolean hasNext()
| {
| if(_nextItem != null)
| {
| return true;
| }
| if(_nestedItems != null)
| {
| if(_nestedItems.hasNext())
| {
| return true;
| }
| _nestedItems = null;
| }
| if (_childs.hasNext())
| {
| UIComponent child = (UIComponent) _childs.next();
| if (child instanceof UISelectItem)
| {
| UISelectItem uiSelectItem = (UISelectItem) child;
| Object item = uiSelectItem.getValue();
| if (item == null)
| {
| Object itemValue = ((UISelectItem) child).getItemValue();
| String label = ((UISelectItem) child).getItemLabel();
| String description = ((UISelectItem) child)
| .getItemDescription();
| boolean disabled = ((UISelectItem) child).isItemDisabled();
| if (label == null)
| {
| label = itemValue.toString();
| }
| item = new SelectItem(itemValue, label, description,
| disabled);
| }
| else if (!(item instanceof SelectItem))
| {
| ValueBinding binding = ((UISelectItem) child)
| .getValueBinding("value");
| throw new IllegalArgumentException(
| "Value binding '"
| + (binding == null ? null :
binding.getExpressionString())
| + "' of UISelectItem : "
| + getPathToComponent(child)
| + " does not reference an Object of type
SelectItem");
| }
| _nextItem = item;
| return true;
| }
| else if (child instanceof UISelectItems)
| {
| _currentUISelectItems = ((UISelectItems) child);
| Object value = _currentUISelectItems.getValue();
|
| if (value instanceof SelectItem)
| {
| _nextItem = value;
| return true;
| }
| else if (value instanceof SelectItem[])
| {
| _nestedItems = Arrays.asList((SelectItem[]) value)
| .iterator();
| _collectionLabel = "Array";
| return hasNext();
| }
| else if (value instanceof Collection)
| {
| _nestedItems = ((Collection)value).iterator();
| _collectionLabel = "Collection";
| return hasNext();
| }
| else if (value instanceof Map)
| {
| Map map = ((Map) value);
| Collection items = new ArrayList(map.size());
| for (Iterator it = map.entrySet().iterator(); it
| .hasNext();)
| {
| Map.Entry entry = (Map.Entry) it.next();
| items.add(new SelectItem(entry.getValue(), entry
| .getKey().toString()));
| }
| _nestedItems = items.iterator();
| _collectionLabel = "Map";
| return hasNext();
| }
| else
| {
| ValueBinding binding =
_currentUISelectItems.getValueBinding("value");
|
| throw new IllegalArgumentException(
| "Value binding '"
| + (binding == null ? null : binding
| .getExpressionString())
| + "'of UISelectItems with component-path "
| + getPathToComponent(child)
| + " does not reference an Object of type SelectItem,
SelectItem[], Collection or Map but of type : "
| + ((value == null) ? null : value
| .getClass()
| .getName()));
| }
| }
| else
| {
| //todo: may other objects than selectItems be nested or not?
| //log.error("Invalid component : " +
getPathToComponent(child) + " : must be UISelectItem or UISelectItems, is of type :
"+((child==null)?"null":child.getClass().getName()));
| }
| }
| return false;
| }
|
| public SelectItem next()
| {
| if (!hasNext())
| {
| throw new NoSuchElementException();
| }
| if(_nextItem != null)
| {
| Object value = _nextItem;
| _nextItem = null;
| return (SelectItem) value;
| }
| if (_nestedItems != null)
| {
| Object item = _nestedItems.next();
| if (!(item instanceof SelectItem))
| {
| ValueBinding binding = _currentUISelectItems
| .getValueBinding("value");
| throw new IllegalArgumentException(
| _collectionLabel + " referenced by UISelectItems with binding
'"
| + (binding == null ? null : binding
| .getExpressionString())
| + "' and Component-Path : " +
getPathToComponent(_currentUISelectItems)
| + " does not contain Objects of type SelectItem");
| }
| return (SelectItem) item;
| }
| throw new NoSuchElementException();
| }
|
| public void remove()
| {
| throw new UnsupportedOperationException();
| }
|
|
| private String getPathToComponent(UIComponent component)
| {
| StringBuffer buf = new StringBuffer();
|
| if(component == null)
| {
| buf.append("{Component-Path : ");
| buf.append("[null]}");
| return buf.toString();
| }
|
| getPathToComponent(component,buf);
|
| buf.insert(0,"{Component-Path : ");
| buf.append("}");
|
| return buf.toString();
| }
|
| private void getPathToComponent(UIComponent component, StringBuffer buf)
| {
| if(component == null)
| return;
|
| StringBuffer intBuf = new StringBuffer();
|
| intBuf.append("[Class: ");
| intBuf.append(component.getClass().getName());
| if(component instanceof UIViewRoot)
| {
| intBuf.append(",ViewId: ");
| intBuf.append(((UIViewRoot) component).getViewId());
| }
| else
| {
| intBuf.append(",Id: ");
| intBuf.append(component.getId());
| }
| intBuf.append("]");
|
| buf.insert(0,intBuf);
|
| if(component!=null)
| {
| getPathToComponent(component.getParent(),buf);
| }
| }
| }
|
View the original post :
http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4100785#...
Reply to the post :
http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&a...