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;
}