You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by lu...@apache.org on 2009/10/08 23:47:25 UTC
svn commit: r823338 -
/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/renderkit/_SharedRendererUtils.java
Author: lu4242
Date: Thu Oct 8 21:47:24 2009
New Revision: 823338
URL: http://svn.apache.org/viewvc?rev=823338&view=rev
Log:
MYFACES-2136 UISelectMany
Modified:
myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/renderkit/_SharedRendererUtils.java
Modified: myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/renderkit/_SharedRendererUtils.java
URL: http://svn.apache.org/viewvc/myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/renderkit/_SharedRendererUtils.java?rev=823338&r1=823337&r2=823338&view=diff
==============================================================================
--- myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/renderkit/_SharedRendererUtils.java (original)
+++ myfaces/shared/trunk_4.0.x/core/src/main/java/org/apache/myfaces/shared/renderkit/_SharedRendererUtils.java Thu Oct 8 21:47:24 2009
@@ -18,8 +18,16 @@
*/
package org.apache.myfaces.shared.renderkit;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.Queue;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import javax.el.ValueExpression;
import javax.faces.FacesException;
@@ -28,9 +36,9 @@
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.convert.ConverterException;
-import java.lang.reflect.Array;
-import java.util.ArrayList;
-import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
/**
* The util methods in this class are shared between the javax.faces.component package and
@@ -42,23 +50,30 @@
*/
class _SharedRendererUtils
{
- static Converter findUIOutputConverter(FacesContext facesContext, UIOutput component)
+ static final String COLLECTION_TYPE_KEY = "collectionType";
+
+ static Converter findUIOutputConverter(FacesContext facesContext,
+ UIOutput component)
{
// Attention!
// This code is duplicated in jsfapi component package.
// If you change something here please do the same in the other class!
Converter converter = component.getConverter();
- if (converter != null) return converter;
+ if (converter != null)
+ return converter;
//Try to find out by value expression
ValueExpression expression = component.getValueExpression("value");
- if (expression == null) return null;
+ if (expression == null)
+ return null;
Class valueType = expression.getType(facesContext.getELContext());
- if (valueType == null) return null;
+ if (valueType == null)
+ return null;
- if (Object.class.equals(valueType)) return null; //There is no converter for Object class
+ if (Object.class.equals(valueType))
+ return null; //There is no converter for Object class
try
{
@@ -66,154 +81,244 @@
}
catch (FacesException e)
{
- log(facesContext, "No Converter for type " + valueType.getName() + " found", e);
+ log(facesContext, "No Converter for type " + valueType.getName()
+ + " found", e);
return null;
}
}
static Object getConvertedUISelectManyValue(FacesContext facesContext,
- UISelectMany component,
- String[] submittedValue)
+ UISelectMany component, String[] submittedValue)
throws ConverterException
{
// Attention!
// This code is duplicated in jsfapi component package.
// If you change something here please do the same in the other class!
- if (submittedValue == null) throw new NullPointerException("submittedValue");
-
- ValueExpression expression = component.getValueExpression("value");
- Class valueType = null;
- Class arrayComponentType = null;
- if (expression != null)
+ if (submittedValue == null)
{
- //By some strange reason vb.getType(facesContext.getELContext());
- //does not return the same as vb.getValue(facesContext.getELContext()).getClass(),
- //so we need to use this instead.
- Object value = expression.getValue(facesContext.getELContext());
- valueType = (value != null) ? value.getClass() :
- expression.getType(facesContext.getELContext()) ;
-
- if (valueType != null && valueType.isArray())
- {
- arrayComponentType = valueType.getComponentType();
- }
+ throw new NullPointerException("submittedValue");
}
-
+
+ ValueExpression expression = component.getValueExpression("value");
+ Object targetForConvertedValues = null;
+ // if the component has an attached converter, use it
Converter converter = component.getConverter();
- if (converter == null)
+ if (expression != null)
{
- if (valueType == null)
+ Class<?> modelType = expression
+ .getType(facesContext.getELContext());
+ if (modelType.isArray())
{
- // No converter, and no idea of expected type
- // --> return the submitted String array
- return submittedValue;
- }
-
- if (List.class.isAssignableFrom(valueType))
- {
- // expected type is a List
- // --> according to javadoc of UISelectMany we assume that the element type
- // is java.lang.String, and copy the String array to a new List
- int len = submittedValue.length;
- List lst = new ArrayList(len);
- for (int i = 0; i < len; i++)
+ // 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))
{
- lst.add(submittedValue[i]);
+ return submittedValue;
}
- return lst;
+ 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);
}
-
- if (arrayComponentType == null)
+ else if (Collection.class.isAssignableFrom(modelType))
{
- throw new IllegalArgumentException("ValueBinding for UISelectMany must be of type List or Array");
+ // 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);
+ }
+ }
+ }
+ }
}
-
- if (Object.class.equals(arrayComponentType)) return submittedValue; //No conversion for Object class
-
- converter = facesContext.getApplication().createConverter(arrayComponentType);
-
- if (converter == null)
+ else
{
- return submittedValue;
+ // 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];
+ }
- // Now, we have a converter...
- // We determine the type of the component array after converting one of it's elements
- if (expression != null)
+ // 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++)
{
- valueType = expression.getType(facesContext.getELContext());
- if (valueType != null && valueType.isArray())
+ // get the value
+ Object value;
+ if (converter != null)
{
- if (submittedValue.length > 0)
- {
- arrayComponentType = converter.getAsObject(facesContext, component, submittedValue[0]).getClass();
- }
+ value = converter.getAsObject(facesContext, component,
+ submittedValue[i]);
}
- }
-
- if (valueType == null)
- {
- // ...but have no idea of expected type
- // --> so let's convert it to an Object array
- int len = submittedValue.length;
- Object [] convertedValues = (Object []) Array.newInstance(
- arrayComponentType==null?Object.class:arrayComponentType,len);
- for (int i = 0; i < len; i++)
+ else
{
- convertedValues[i]
- = converter.getAsObject(facesContext, component, submittedValue[i]);
+ value = submittedValue[i];
}
- return convertedValues;
- }
-
- if (List.class.isAssignableFrom(valueType))
- {
- // Curious case: According to specs we should assume, that the element type
- // of this List is java.lang.String. But there is a Converter set for this
- // component. Because the user must know what he is doing, we will convert the values.
- int len = submittedValue.length;
- List lst = new ArrayList(len);
- for (int i = 0; i < len; i++)
+ // store it in targetForConvertedValues
+ if (isArray)
{
- lst.add(converter.getAsObject(facesContext, component, submittedValue[i]));
+ Array.set(targetForConvertedValues, i, value);
}
- return lst;
- }
-
- if (arrayComponentType == null)
- {
- throw new IllegalArgumentException("ValueBinding for UISelectMany must be of type List or Array");
- }
-
- if (arrayComponentType.isPrimitive())
- {
- //primitive array
- int len = submittedValue.length;
- Object convertedValues = Array.newInstance(arrayComponentType, len);
- for (int i = 0; i < len; i++)
+ else
{
- Array.set(convertedValues, i,
- converter.getAsObject(facesContext, component, submittedValue[i]));
+ ((Collection) targetForConvertedValues).add(value);
}
- return convertedValues;
}
- //Object array
- int len = submittedValue.length;
- ArrayList convertedValues = new ArrayList(len);
- for (int i = 0; i < len; i++)
- {
- convertedValues.add(i, converter.getAsObject(facesContext, component, submittedValue[i]));
- }
- return convertedValues.toArray((Object[]) Array.newInstance(arrayComponentType, len));
-
+ return targetForConvertedValues;
}
-
-
- private static final Log log = LogFactory.getLog(_SharedRendererUtils.class);
+ private static final Log log = LogFactory
+ .getLog(_SharedRendererUtils.class);
/**
* This method is different in the two versions of _SharedRendererUtils.