You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2009/11/27 01:56:56 UTC

svn commit: r884731 - in /myfaces/core/trunk/api/src/main/java/javax/faces/component: _SelectItemsIterator.java _SharedRendererUtils.java

Author: lu4242
Date: Fri Nov 27 00:56:56 2009
New Revision: 884731

URL: http://svn.apache.org/viewvc?rev=884731&view=rev
Log:
MYFACES-2418 Implement h:selectManyXXX collectionType and hideNoSelectionOption (thanks to Jakob Korherr for this patch)

Modified:
    myfaces/core/trunk/api/src/main/java/javax/faces/component/_SelectItemsIterator.java
    myfaces/core/trunk/api/src/main/java/javax/faces/component/_SharedRendererUtils.java

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/_SelectItemsIterator.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/_SelectItemsIterator.java?rev=884731&r1=884730&r2=884731&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/_SelectItemsIterator.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/_SelectItemsIterator.java Fri Nov 27 00:56:56 2009
@@ -53,7 +53,6 @@
     private final Iterator<UIComponent> _children;
     private Iterator<? extends Object> _nestedItems;
     private SelectItem _nextItem;
-    private String _collectionLabel;
     private UISelectItems _currentUISelectItems;
     private FacesContext _facesContext;
 
@@ -152,22 +151,12 @@
                         items.add(Array.get(value, i));
                     }
                     _nestedItems = items.iterator();
-                    _collectionLabel = "Array";
                     return hasNext();
                 }
                 else if (value instanceof Iterable)
                 {
                     // value is Iterable --> Collection, DataModel,...
                     _nestedItems = ((Iterable<?>) value).iterator();
-                    // For better understanding ask if value is a Collection
-                    if (value instanceof Collection)
-                    {
-                        _collectionLabel = "Collection";
-                    }
-                    else
-                    {
-                        _collectionLabel = "Iterable";
-                    }
                     return hasNext();
                 }
                 else if (value instanceof Map)
@@ -180,7 +169,6 @@
                     }
                     
                     _nestedItems = items.iterator();
-                    _collectionLabel = "Map";
                     return hasNext();
                 }
                 else
@@ -232,66 +220,57 @@
                     oldRequestMapVarValue = _facesContext.getExternalContext().getRequestMap().put(var, item);
                     wroteRequestMapVarValue = true;
                 }
-                try
+                
+                // check the itemValue attribute
+                Object itemValue = attributeMap.get(ITEM_VALUE_ATTR);
+                if (itemValue == null)
+                {
+                    // the itemValue attribute was not provided
+                    // --> use the current item as the itemValue
+                    itemValue = item;
+                }
+                
+                // Spec: When iterating over the select items, toString() 
+                // must be called on the string rendered attribute values
+                Object itemLabel = attributeMap.get(ITEM_LABEL_ATTR);
+                if (itemLabel == null)
+                {
+                    itemLabel = itemValue.toString();
+                }
+                else
                 {
-                    Object itemValue = attributeMap.get(ITEM_VALUE_ATTR);
-                    if(itemValue != null) 
+                    itemLabel = itemLabel.toString();
+                }
+                Object itemDescription = attributeMap.get(ITEM_DESCRIPTION_ATTR);
+                if (itemDescription != null)
+                {
+                    itemDescription = itemDescription.toString();
+                }
+                Boolean itemDisabled = getBooleanAttribute(_currentUISelectItems, ITEM_DISABLED_ATTR, false);
+                Boolean itemLabelEscaped = getBooleanAttribute(_currentUISelectItems, ITEM_LABEL_ESCAPED_ATTR, true);
+                Object noSelectionValue = attributeMap.get(NO_SELECTION_VALUE_ATTR);
+                item = new SelectItem(itemValue,
+                        (String) itemLabel,
+                        (String) itemDescription,
+                        itemDisabled,
+                        itemLabelEscaped,
+                        itemValue.equals(noSelectionValue)); 
+                    
+                // remove the value with the key from var from the request map, if previously written
+                if(wroteRequestMapVarValue)
+                {
+                    // If there was a previous value stored with the key from var in the request map, restore it
+                    if (oldRequestMapVarValue != null)
                     {
-                        // Spec: When iterating over the select items, toString() 
-                        // must be called on the string rendered attribute values
-                        Object itemLabel = attributeMap.get(ITEM_LABEL_ATTR);
-                        if (itemLabel == null)
-                        {
-                            itemLabel = itemValue.toString();
-                        }
-                        else
-                        {
-                            itemLabel = itemLabel.toString();
-                        }
-                        Object itemDescription = attributeMap.get(ITEM_DESCRIPTION_ATTR);
-                        if (itemDescription != null)
-                        {
-                            itemDescription.toString();
-                        }
-                        Boolean itemDisabled = getBooleanAttribute(_currentUISelectItems, ITEM_DISABLED_ATTR, false);
-                        Boolean itemLabelEscaped = getBooleanAttribute(_currentUISelectItems, ITEM_LABEL_ESCAPED_ATTR, true);
-                        Object noSelectionValue = attributeMap.get(NO_SELECTION_VALUE_ATTR);
-                        item = new SelectItem(itemValue,
-                                (String) itemLabel,
-                                (String) itemDescription,
-                                itemDisabled,
-                                itemLabelEscaped,
-                                itemValue.equals(noSelectionValue)); 
+                        _facesContext.getExternalContext()
+                                .getRequestMap().put(var, oldRequestMapVarValue);
                     }
-                    else 
+                    else
                     {
-                        ValueExpression expression = _currentUISelectItems.getValueExpression("value");
-                        throw new IllegalArgumentException(
-                                _collectionLabel + " referenced by UISelectItems with ValueExpression '"
-                                + expression.getExpressionString()
-                                + "' and Component-Path : " + getPathToComponent(_currentUISelectItems)
-                                + " does not contain Objects of type SelectItem"
-                                + " or does not provide the attribute itemValue");
+                        _facesContext.getExternalContext()
+                                .getRequestMap().remove(var);
                     }
-                }
-                finally
-                {
-                    // remove the value with the key from var from the request map, if previously written
-                    if(wroteRequestMapVarValue)
-                    {
-                        // If there was a previous value stored with the key from var in the request map, restore it
-                        if (oldRequestMapVarValue != null)
-                        {
-                            _facesContext.getExternalContext()
-                                    .getRequestMap().put(var, oldRequestMapVarValue);
-                        }
-                        else
-                        {
-                            _facesContext.getExternalContext()
-                                    .getRequestMap().remove(var);
-                        }
-                    } 
-                }
+                } 
             }
             return (SelectItem) item;
         }

Modified: myfaces/core/trunk/api/src/main/java/javax/faces/component/_SharedRendererUtils.java
URL: http://svn.apache.org/viewvc/myfaces/core/trunk/api/src/main/java/javax/faces/component/_SharedRendererUtils.java?rev=884731&r1=884730&r2=884731&view=diff
==============================================================================
--- myfaces/core/trunk/api/src/main/java/javax/faces/component/_SharedRendererUtils.java (original)
+++ myfaces/core/trunk/api/src/main/java/javax/faces/component/_SharedRendererUtils.java Fri Nov 27 00:56:56 2009
@@ -21,8 +21,10 @@
 import java.lang.reflect.Array;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.Queue;
 import java.util.Set;
@@ -34,6 +36,8 @@
 import javax.faces.context.FacesContext;
 import javax.faces.convert.Converter;
 import javax.faces.convert.ConverterException;
+import javax.faces.model.SelectItem;
+import javax.faces.model.SelectItemGroup;
 
 /**
  * The util methods in this class are shared between the javax.faces.component package and the
@@ -137,136 +141,159 @@
                 targetForConvertedValues = Array.newInstance(componentType,
                         submittedValue.length);
             }
-            else if (Collection.class.isAssignableFrom(modelType))
+            else if (Collection.class.isAssignableFrom(modelType) || Object.class.equals(modelType))
             {
-                // the target should be a Collection
-                Object collectionTypeAttr = component.getAttributes().get(
-                        COLLECTION_TYPE_KEY);
-                if (collectionTypeAttr != null)
+                if (converter == null)
                 {
-                    Class<?> collectionType = null;
-                    // if there is a value, it must be a ...
-                    // ... a ValueExpression that evaluates to a String or a Class
-                    if (collectionTypeAttr instanceof ValueExpression)
-                    {
-                        // get the value of the ValueExpression
-                        collectionTypeAttr = ((ValueExpression) collectionTypeAttr)
-                                .getValue(facesContext.getELContext());
-                    }
-                    // ... String that is a fully qualified Java class name
-                    if (collectionTypeAttr instanceof String)
+                    // try to get the by-type-converter from the type of the SelectItems
+                    _SelectItemsIterator iterator = new _SelectItemsIterator(component, facesContext);
+                    converter = getSelectItemsValueConverter(iterator, facesContext);
+                }
+                
+                if (Collection.class.isAssignableFrom(modelType))
+                {
+                    // the target should be a Collection
+                    Object collectionTypeAttr = component.getAttributes().get(
+                            COLLECTION_TYPE_KEY);
+                    if (collectionTypeAttr != null)
                     {
-                        try
+                        Class<?> collectionType = null;
+                        // if there is a value, it must be a ...
+                        // ... a ValueExpression that evaluates to a String or a Class
+                        if (collectionTypeAttr instanceof ValueExpression)
+                        {
+                            // get the value of the ValueExpression
+                            collectionTypeAttr = ((ValueExpression) collectionTypeAttr)
+                                    .getValue(facesContext.getELContext());
+                        }
+                        // ... String that is a fully qualified Java class name
+                        if (collectionTypeAttr instanceof String)
+                        {
+                            try
+                            {
+                                collectionType = Class
+                                        .forName((String) collectionTypeAttr);
+                            }
+                            catch (ClassNotFoundException cnfe)
+                            {
+                                throw new FacesException(
+                                        "Unable to find class "
+                                                + collectionTypeAttr
+                                                + " on the classpath.", cnfe);
+                            }
+    
+                        }
+                        // ... a Class object
+                        else if (collectionTypeAttr instanceof Class)
                         {
-                            collectionType = Class
-                                    .forName((String) collectionTypeAttr);
+                            collectionType = (Class<?>) collectionTypeAttr;
                         }
-                        catch (ClassNotFoundException cnfe)
+                        else
                         {
                             throw new FacesException(
-                                    "Unable to find class "
-                                            + collectionTypeAttr
-                                            + " on the classpath.", cnfe);
+                                    "The attribute "
+                                            + COLLECTION_TYPE_KEY
+                                            + " of component "
+                                            + component.getClientId()
+                                            + " does not evaluate to a "
+                                            + "String, a Class object or a ValueExpression pointing "
+                                            + "to a String or a Class object.");
                         }
-
-                    }
-                    // ... a Class object
-                    else if (collectionTypeAttr instanceof Class)
-                    {
-                        collectionType = (Class<?>) collectionTypeAttr;
-                    }
-                    else
-                    {
-                        throw new FacesException(
-                                "The attribute "
-                                        + COLLECTION_TYPE_KEY
-                                        + " of component "
-                                        + component.getClientId()
-                                        + " does not evaluate to a "
-                                        + "String, a Class object or a ValueExpression pointing "
-                                        + "to a String or a Class object.");
-                    }
-                    // now we have a collectionType --> but is it really some kind of Collection
-                    if (!Collection.class.isAssignableFrom(collectionType))
-                    {
-                        throw new FacesException("The attribute "
-                                + COLLECTION_TYPE_KEY + " of component "
-                                + component.getClientId()
-                                + " does not point to a valid type of Collection.");
-                    }
-                    // now we have a real collectionType --> try to instantiate it
-                    try
-                    {
-                        targetForConvertedValues = collectionType.newInstance();
-                    }
-                    catch (Exception e)
-                    {
-                        throw new FacesException("The Collection "
-                                + collectionType.getName()
-                                + "can not be instantiated.", e);
-                    }
-                }
-                else
-                {
-                    // component.getValue() will implement Collection at this point
-                    Collection<?> componentValue = (Collection<?>) component
-                            .getValue();
-                    // can we clone the Collection
-                    if (componentValue instanceof Cloneable)
-                    {
-                        // clone method of Object is protected --> use reflection
+                        // now we have a collectionType --> but is it really some kind of Collection
+                        if (!Collection.class.isAssignableFrom(collectionType))
+                        {
+                            throw new FacesException("The attribute "
+                                    + COLLECTION_TYPE_KEY + " of component "
+                                    + component.getClientId()
+                                    + " does not point to a valid type of Collection.");
+                        }
+                        // now we have a real collectionType --> try to instantiate it
                         try
                         {
-                            Method cloneMethod = componentValue.getClass()
-                                    .getMethod("clone");
-                            Collection<?> clone = (Collection<?>) cloneMethod
-                                    .invoke(componentValue);
-                            clone.clear();
-                            targetForConvertedValues = clone;
+                            targetForConvertedValues = collectionType.newInstance();
                         }
                         catch (Exception e)
                         {
-                            log(facesContext, "Could not clone "
-                                    + componentValue.getClass().getName(), e);
+                            throw new FacesException("The Collection "
+                                    + collectionType.getName()
+                                    + "can not be instantiated.", e);
                         }
                     }
-
-                    // if clone did not work
-                    if (targetForConvertedValues == null)
+                    else
                     {
-                        // try to create the (concrete) collection from modelType 
-                        // or with the class object of componentValue (if any)
-                        try
+                        // component.getValue() will implement Collection at this point
+                        Collection<?> componentValue = (Collection<?>) component
+                                .getValue();
+                        // can we clone the Collection
+                        if (componentValue instanceof Cloneable)
                         {
-                            targetForConvertedValues = (componentValue != null ? componentValue
-                                    .getClass()
-                                    : modelType).newInstance();
-                        }
-                        catch (Exception e)
-                        {
-                            // this did not work either
-                            // use the standard concrete type
-                            if (SortedSet.class.isAssignableFrom(modelType))
+                            // clone method of Object is protected --> use reflection
+                            try
                             {
-                                targetForConvertedValues = new TreeSet();
+                                Method cloneMethod = componentValue.getClass()
+                                        .getMethod("clone");
+                                Collection<?> clone = (Collection<?>) cloneMethod
+                                        .invoke(componentValue);
+                                clone.clear();
+                                targetForConvertedValues = clone;
                             }
-                            else if (Queue.class.isAssignableFrom(modelType))
+                            catch (Exception e)
                             {
-                                targetForConvertedValues = new LinkedList();
+                                log(facesContext, "Could not clone "
+                                        + componentValue.getClass().getName(), e);
                             }
-                            else if (Set.class.isAssignableFrom(modelType))
+                        }
+    
+                        // if clone did not work
+                        if (targetForConvertedValues == null)
+                        {
+                            // try to create the (concrete) collection from modelType 
+                            // or with the class object of componentValue (if any)
+                            try
                             {
-                                targetForConvertedValues = new HashSet(
-                                        submittedValue.length);
+                                targetForConvertedValues = (componentValue != null ? componentValue
+                                        .getClass()
+                                        : modelType).newInstance();
                             }
-                            else
+                            catch (Exception e)
                             {
-                                targetForConvertedValues = new ArrayList(
-                                        submittedValue.length);
+                                // this did not work either
+                                // use the standard concrete type
+                                if (SortedSet.class.isAssignableFrom(modelType))
+                                {
+                                    targetForConvertedValues = new TreeSet();
+                                }
+                                else if (Queue.class.isAssignableFrom(modelType))
+                                {
+                                    targetForConvertedValues = new LinkedList();
+                                }
+                                else if (Set.class.isAssignableFrom(modelType))
+                                {
+                                    targetForConvertedValues = new HashSet(
+                                            submittedValue.length);
+                                }
+                                else
+                                {
+                                    targetForConvertedValues = new ArrayList(
+                                            submittedValue.length);
+                                }
                             }
                         }
                     }
                 }
+                else /* if (Object.class.equals(modelType)) */
+                {
+                    // a modelType of Object is also permitted, in order to support
+                    // managed bean properties of type Object
+                    
+                    // optimization: if we don't have a converter, we can return the submittedValue
+                    if (converter == null)
+                    {
+                        return submittedValue;
+                    }
+                    
+                    targetForConvertedValues = new Object[submittedValue.length];
+                }
             }
             else
             {
@@ -309,6 +336,51 @@
 
         return targetForConvertedValues;
     }
+    
+    /**
+     * Iterates through the SelectItems with the given Iterator and tries to obtain
+     * a by-class-converter based on the Class of SelectItem.getValue().
+     * @param iterator
+     * @param facesContext
+     * @return The first suitable Converter for the given SelectItems or null.
+     */
+    static Converter getSelectItemsValueConverter(Iterator<SelectItem> iterator, FacesContext facesContext)
+    {
+        // Attention!
+        // This code is duplicated in jsfapi component package.
+        // If you change something here please do the same in the other class!
+        
+        Converter converter = null;
+        while (converter == null && iterator.hasNext())
+        {
+            SelectItem item = iterator.next();
+            if (item instanceof SelectItemGroup)
+            {
+                Iterator<SelectItem> groupIterator = Arrays.asList(((SelectItemGroup) item).getSelectItems()).iterator();
+                converter = getSelectItemsValueConverter(groupIterator, facesContext);
+            }
+            else
+            {
+                Class<?> selectItemsType = item.getValue().getClass();
+
+                // optimization: no conversion for String values
+                if (String.class.equals(selectItemsType))
+                {
+                    return null;
+                }
+                
+                try
+                {
+                    converter = facesContext.getApplication().createConverter(selectItemsType);
+                }
+                catch (FacesException e)
+                {
+                    // nothing - try again
+                }
+            }
+        }
+        return converter;
+    }
 
     /**
      * This method is different in the two versions of _SharedRendererUtils.