static Object getConvertedUISelectManyValue()

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