in tobago-core/src/main/java/org/apache/myfaces/tobago/internal/renderkit/renderer/SelectManyRendererBase.java [142:319]
static Object getConvertedUISelectManyValue(
final FacesContext facesContext, final UISelectMany component,
final String[] submittedValue, final 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!
if (submittedValue == null) {
throw new NullPointerException("submittedValue");
}
final ValueExpression expression = component.getValueExpression("value");
Object targetForConvertedValues = null;
// 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) {
final 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
final 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)) {
if (converter == null) {
// try to get the by-type-converter from the type of the SelectItems
final SelectItemsIterator iterator = new SelectItemsIterator(component, facesContext);
converter = getSelectItemsValueConverter(iterator, facesContext);
}
final Object collectionTypeAttr = component.getAttributes().get(
COLLECTION_TYPE_KEY);
if (collectionTypeAttr != null) {
final 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 (final 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
final Collection<?> componentValue = (Collection<?>) component.getValue();
// can we clone the Collection
if (componentValue instanceof Cloneable) {
// clone method of Object is protected --> use reflection
try {
final Method cloneMethod = componentValue.getClass()
.getMethod("clone");
final Collection<?> clone = (Collection<?>) cloneMethod
.invoke(componentValue);
clone.clear();
targetForConvertedValues = clone;
} catch (final Exception e) {
LOG.error("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 (final 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
final boolean isArray = targetForConvertedValues.getClass().isArray();
for (int i = 0; i < submittedValue.length; i++) {
// get the value
final 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 {
((Collection) targetForConvertedValues).add(value);
}
}
return targetForConvertedValues;
}