}
ValueExpression expression = component.getValueExpression("value");
Object targetForConvertedValues = null;
// if the component has an attached converter, use it
Converter converter = component.getConverter();
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)
{
// could not obtain a Converter
// --> check if we maybe do not really have to convert
if (!Object.class.equals(componentType))
{
// 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))
{
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);
}
if (Collection.class.isAssignableFrom(modelType))
{
// the target should be a Collection
Object collectionTypeAttr = component.getAttributes().get(
COLLECTION_TYPE_KEY);
if (collectionTypeAttr != 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
{
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<?>) 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
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];