Commits

unkyaku  committed 5f4358d

Add support for type converting indexed collection elements.
Make "Collection_" a constant.

git-svn-id: http://svn.opensymphony.com/svn/xwork/trunk@307e221344d-f017-0410-9bd5-d282ab1896d7

  • Participants
  • Parent commits ea1d998

Comments (0)

Files changed (4)

File src/java/com/opensymphony/xwork/util/InstantiatingNullHandler.java

 
 import ognl.NullHandler;
 import ognl.Ognl;
-import ognl.OgnlContext;
 import ognl.OgnlRuntime;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 
 import java.util.Collection;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
         }
 
         try {
+            String propName = property.toString();
+            Object realTarget = OgnlUtil.getRealTarget(propName, context, target);
             Class clazz = null;
-            Object realTarget = target;
 
-            // find real target
-            if (target instanceof CompoundRoot) {
-                CompoundRoot root = (CompoundRoot) target;
-
-                for (Iterator iterator = root.iterator(); iterator.hasNext();) {
-                    realTarget = iterator.next();
-
-                    if (OgnlRuntime.hasSetProperty((OgnlContext) context, realTarget, property.toString())) {
-                        clazz = OgnlRuntime.getPropertyDescriptor(realTarget.getClass(), property.toString()).getPropertyType();
-
-                        break;
-                    }
-                }
-            } else {
-                clazz = OgnlRuntime.getPropertyDescriptor(realTarget.getClass(), property.toString()).getPropertyType();
+            if (realTarget != null) {
+                clazz = OgnlRuntime.getPropertyDescriptor(realTarget.getClass(), propName).getPropertyType();
             }
 
             if (clazz == null) {
                 return null;
             }
 
-            Object param = createObject(clazz, realTarget, property.toString());
+            Object param = createObject(clazz, realTarget, propName);
 
-            Ognl.setValue(property.toString(), context, realTarget, param);
+            Ognl.setValue(propName, context, realTarget, param);
 
             return param;
         } catch (Exception e) {
     }
 
     protected Class getCollectionType(Class clazz, String property) {
-        return (Class) XWorkConverter.getInstance().getConverter(clazz, "Collection_" + property);
+        return (Class) XWorkConverter.getInstance().getConverter(clazz, XWorkConverter.CONVERSION_COLLECTION_PREFIX + property);
     }
 
     private Object createObject(Class clazz, Object target, String property) throws Exception {

File src/java/com/opensymphony/xwork/util/OgnlUtil.java

 package com.opensymphony.xwork.util;
 
 import ognl.Ognl;
+import ognl.OgnlContext;
 import ognl.OgnlException;
+import ognl.OgnlRuntime;
+import ognl.TypeConverter;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
     //~ Methods ////////////////////////////////////////////////////////////////
 
     /**
-     * Sets the object's properties using the default type converter, defaulting to not throw exceptions for problems setting the properties.
+     * Sets the object's properties using the default type converter, defaulting to not throw
+     * exceptions for problems setting the properties.
      *
      * @param props the properties being set
      * @param o the object
      * @param props the properties being set
      * @param o the object
      * @param context the action context
-     * @param throwPropertyExceptions boolean which tells whether it should throw exceptions for problems setting the properties
+     * @param throwPropertyExceptions boolean which tells whether it should throw exceptions for
+     * problems setting the properties
      */
     public static void setProperties(Map props, Object o, Map context, boolean throwPropertyExceptions) {
         if (props == null) {
     }
 
     /**
-     * Sets the properties on the object using the default context, defaulting to not throwing exceptions for problems setting the properties.
+     * Sets the properties on the object using the default context, defaulting to not throwing
+     * exceptions for problems setting the properties.
+     *
      * @param properties
      * @param o
      */
     }
 
     /**
-     * Sets the properties on the object using the default context
+     * Sets the properties on the object using the default context.
+     *
      * @param properties the property map to set on the object
      * @param o the object to set the properties into
-     * @param throwPropertyExceptions boolean which tells whether it should throw exceptions for problems setting the properties
+     * @param throwPropertyExceptions boolean which tells whether it should throw exceptions for
+     * problems setting the properties
      */
     public static void setProperties(Map properties, Object o, boolean throwPropertyExceptions) {
         Map context = Ognl.createDefaultContext(o);
     }
 
     /**
-     * Sets the named property to the supplied value on the Object, defaults to not throwing property exceptions
+     * Sets the named property to the supplied value on the Object, defaults to not throwing
+     * property exceptions.
+     *
      * @param name the name of the property to be set
      * @param value the value to set into the named property
      * @param o the object upon which to set the property
     }
 
     /**
-     * Sets the named property to the supplied value on the Object
+     * Sets the named property to the supplied value on the Object.
+     *
      * @param name the name of the property to be set
      * @param value the value to set into the named property
      * @param o the object upon which to set the property
      * @param context the context which may include the TypeConverter
-     * @param throwPropertyExceptions boolean which tells whether it should throw exceptions for problems setting the property
+     * @param throwPropertyExceptions boolean which tells whether it should throw exceptions for
+     * problems setting the property
      */
     public static void setProperty(String name, Object value, Object o, Map context, boolean throwPropertyExceptions) {
         Ognl.setTypeConverter(context, XWorkConverter.getInstance());
         Ognl.setRoot(context, oldRoot);
     }
 
+    /**
+     * Looks for the real target with the specified property given a root Object which may be a
+     * CompoundRoot.
+     *
+     * @return the real target or null if no object can be found with the specified property
+     */
+    public static Object getRealTarget(String property, Map context, Object root) throws OgnlException {
+        if (root instanceof CompoundRoot) {
+            // find real target
+            CompoundRoot cr = (CompoundRoot) root;
+
+            try {
+                for (Iterator iterator = cr.iterator(); iterator.hasNext();) {
+                    Object target = iterator.next();
+
+                    if (OgnlRuntime.hasSetProperty((OgnlContext) context, target, property)) {
+                        return target;
+                    }
+                }
+            } catch (IntrospectionException ex) {
+                throw new OgnlException("Cannot figure out real target class", ex);
+            }
+
+            return null;
+        }
+
+        return root;
+    }
+
+    /**
+     * Wrapper around Ognl.setValue() to handle type conversion for collection elements.
+     * Ideally, this should be handled by OGNL directly.
+     */
+    public static void setValue(String name, Map context, Object root, Object value) throws OgnlException {
+        if (name.endsWith("]")) {
+            String property = name.substring(0, name.lastIndexOf("["));
+            Object target = getRealTarget(property, context, root);
+
+            if (target != null) {
+                Class memberType = (Class) XWorkConverter.getInstance().getConverter(target.getClass(), XWorkConverter.CONVERSION_COLLECTION_PREFIX + property);
+
+                if (memberType != null) {
+                    TypeConverter converter = Ognl.getTypeConverter(context);
+                    value = converter.convertValue(context, target, null, property, value, memberType);
+                }
+            }
+        }
+
+        Ognl.setValue(compile(name), context, root, value);
+    }
+
     public static Object compile(String expression) throws OgnlException {
         Object o = expressions.get(expression);
 
 
     /**
      * Copies the properties in the object "from" and sets them in the object "to"
-     * using specified type converter, or {@link com.opensymphony.xwork.util.XWorkConverter} if none is specified.
+     * using specified type converter, or {@link com.opensymphony.xwork.util.XWorkConverter} if none
+     * is specified.
      *
      * @param from the source object
      * @param to the target object
 
     static void internalSetProperty(String name, Object value, Object o, Map context, boolean throwPropertyExceptions) {
         try {
-            Ognl.setValue(compile(name), context, o, value);
+            setValue(name, context, o, value);
         } catch (OgnlException e) {
             Throwable reason = e.getReason();
             String msg = "Caught OgnlException while setting property '" + name + "' on type '" + o.getClass().getName() + "'.";

File src/java/com/opensymphony/xwork/util/OgnlValueStack.java

 
         try {
             context.put(XWorkConverter.CONVERSION_PROPERTY_FULLNAME, expr);
-            context.put(REPORT_ERRORS_ON_NO_PROP, new Boolean(throwExceptionOnFailure));
-            Ognl.setValue(OgnlUtil.compile(expr), context, root, value);
+            context.put(REPORT_ERRORS_ON_NO_PROP, Boolean.valueOf(throwExceptionOnFailure));
+            OgnlUtil.setValue(expr, context, root, value);
         } catch (OgnlException e) {
             // ignore
         } finally {

File src/java/com/opensymphony/xwork/util/XWorkConverter.java

     public static final String REPORT_CONVERSION_ERRORS = "report.conversion.errors";
     public static final String CONVERSION_PROPERTY_FULLNAME = "conversion.property.fullName";
     public static final String CONVERSION_ERROR_PROPERTY_PREFIX = "invalid.fieldvalue.";
+    public static final String CONVERSION_COLLECTION_PREFIX = "Collection_";
 
     //~ Instance fields ////////////////////////////////////////////////////////
 
                         break;
                     }
 
-                    if (!key.startsWith("Collection_")) {
+                    if (!key.startsWith(XWorkConverter.CONVERSION_COLLECTION_PREFIX)) {
                         mapping.put(key, createTypeConverter((String) entry.getValue()));
                     } else {
                         mapping.put(key, Thread.currentThread().getContextClassLoader().loadClass((String) entry.getValue()));