public static Object getConvertedUISelectManyValue()

in api/src/main/java/org/apache/myfaces/core/api/shared/SharedRendererUtils.java [113:357]


    public static Object getConvertedUISelectManyValue(FacesContext facesContext, UISelectMany component,  
            String[] submittedValue, boolean considerValueType) throws ConverterException
    {
        // Attention!
        // This code is duplicated in shared renderkit package (except for considerValueType).
        // If you change something here please do the same in the other class!
        Assert.notNull(submittedValue, "submittedValue");

        ValueExpression expression = component.getValueExpression("value");
        Object targetForConvertedValues = null;

        Boolean isCollectionCase = false;

        // if the component has an attached converter, use it
        Converter converter = component.getConverter();
        // at this point the valueType attribute is handled in shared.
        if (converter == null && considerValueType)
        {
            // try to get a converter from the valueType attribute
            converter = getValueTypeConverter(facesContext, component);
        }
        
        if (expression != null)
        {
            Class<?> modelType = expression.getType(facesContext.getELContext());
            if (modelType == null)
            {
                // FIXME temporal workaround for MYFACES-2552
                return submittedValue;
            }
            else if (modelType.isArray())
            {
                // the target should be an array
                Class<?> componentType = modelType.getComponentType();
                // check for optimization if the target is
                // a string array --> no conversion needed
                if (String.class.equals(componentType))
                {
                    return submittedValue;
                }
                if (converter == null)
                {
                    // the compononent does not have an attached converter
                    // --> try to get a registered-by-class converter
                    converter = facesContext.getApplication().createConverter(componentType);

                    if (converter == null && !Object.class.equals(componentType))
                    {
                        // could not obtain a Converter
                        // --> check if we maybe do not really have to convert

                        // target is not an Object array
                        // and not a String array (checked some lines above)
                        // and we do not have a Converter
                        throw new ConverterException(
                                "Could not obtain a Converter for " + componentType.getName());
                    }
                }
                // instantiate the array
                targetForConvertedValues = Array.newInstance(componentType, submittedValue.length);
            }
            else if (Collection.class.isAssignableFrom(modelType) || Object.class.equals(modelType))
            {
                isCollectionCase = true;
                if (converter == null)
                {
                    // try to get the by-type-converter from the type of the SelectItems
                    SelectItemsIterator iterator = new SelectItemsIterator(component, facesContext);
                    converter = getSelectItemsValueConverter(iterator, facesContext);
                }

                Object collectionTypeAttr = component.getAttributes().get(COLLECTION_TYPE_KEY);
                if (collectionTypeAttr != null)
                {
                    Class<?> collectionType = getClassFromAttribute(facesContext, collectionTypeAttr);
                    if (collectionType == null)
                    {
                        throw new FacesException(
                                "The attribute "
                                        + COLLECTION_TYPE_KEY
                                        + " of component "
                                        + component.getClientId(facesContext)
                                        + " 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(facesContext)
                                + " 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 if (Collection.class.isAssignableFrom(modelType))
                {
                    // 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
                        try
                        {
                            Method cloneMethod = componentValue.getClass().getMethod("clone");
                            Collection<?> clone = (Collection<?>) cloneMethod.invoke(componentValue);
                            clone.clear();
                            targetForConvertedValues = clone;
                        }
                        catch (Exception e)
                        {
                            log(facesContext, "Could not clone " + componentValue.getClass().getName(), e);
                        }
                    }

                    // 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 = (componentValue != null 
                                    ? componentValue.getClass()
                                    : modelType).newInstance();
                        }
                        catch (Exception e)
                        {
                            // 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
            {
                // the expression does neither point to an array nor to a collection
                throw new ConverterException(
                        "ValueExpression for UISelectMany must be of type Collection or Array.");
            }
        }
        else
        {
            targetForConvertedValues = new Object[submittedValue.length];
        }

        // convert the values with the selected converter (if any)
        // and store them in targetForConvertedValues
        boolean isArray = (targetForConvertedValues.getClass().isArray());
        for (int i = 0; i < submittedValue.length; i++)
        {
            // get the value
            Object value;
            if (converter != null)
            {
                value = converter.getAsObject(facesContext, component, submittedValue[i]);
            }
            else
            {
                value = submittedValue[i];
            }
            // store it in targetForConvertedValues
            if (isArray)
            {
                Array.set(targetForConvertedValues, i, value);
            }
            else
            {
                if (isCollectionCase) // Added to Address Spec1422IT 
                {
                    Map<String, Object> availableItems = new HashMap<>();

                    SelectItemsIterator iterator = new SelectItemsIterator(component, facesContext);

                    while (iterator.hasNext())
                    {
                        SelectItem item = iterator.next();

                        if (item instanceof SelectItemGroup group)
                        {
                            for (SelectItem itemFromGroup : group.getSelectItems()) 
                            {
                                String keyString = getConvertedStringValue(
                                    facesContext, component, converter, itemFromGroup); // converter retreived earlier
                                availableItems.put(keyString, itemFromGroup.getValue());
                            }
                        }
                        else
                        {
                            String keyString = getConvertedStringValue(facesContext, component, converter, item);
                            availableItems.put(keyString, item.getValue());
                        }
                    }
                    if (!availableItems.isEmpty())
                    {
                        value = availableItems.get(submittedValue[i]);
                    }
                } 
                ((Collection) targetForConvertedValues).add(value);
            }
        }

        return targetForConvertedValues;
    }