You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2012/03/06 07:26:38 UTC

svn commit: r1297347 - in /struts/struts2/trunk: core/src/main/resources/ xwork-core/src/main/java/com/opensymphony/xwork2/ xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/ xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/...

Author: lukaszlenart
Date: Tue Mar  6 06:26:38 2012
New Revision: 1297347

URL: http://svn.apache.org/viewvc?rev=1297347&view=rev
Log:
WW-3762 - extracts one huge converter into smaller classes and implements better conversion mechanism for collections

Added:
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/ArrayConverter.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/CollectionConverter.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/StringConverter.java
Modified:
    struts/struts2/trunk/core/src/main/resources/struts-default.xml
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverter.java
    struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java
    struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
    struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java

Modified: struts/struts2/trunk/core/src/main/resources/struts-default.xml
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/core/src/main/resources/struts-default.xml?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/core/src/main/resources/struts-default.xml (original)
+++ struts/struts2/trunk/core/src/main/resources/struts-default.xml Tue Mar  6 06:26:38 2012
@@ -63,6 +63,12 @@
     <bean type="com.opensymphony.xwork2.conversion.impl.XWorkConverter" name="xwork1" class="com.opensymphony.xwork2.conversion.impl.XWorkConverter" />
     <bean class="com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter" />
 
+    <bean type="com.opensymphony.xwork2.conversion.TypeConverter" name="collection" class="com.opensymphony.xwork2.conversion.impl.CollectionConverter" scope="singleton"/>
+    <bean type="com.opensymphony.xwork2.conversion.TypeConverter" name="array" class="com.opensymphony.xwork2.conversion.impl.ArrayConverter" scope="singleton"/>
+    <bean type="com.opensymphony.xwork2.conversion.TypeConverter" name="date" class="com.opensymphony.xwork2.conversion.impl.DateConverter" scope="singleton"/>
+    <bean type="com.opensymphony.xwork2.conversion.TypeConverter" name="number" class="com.opensymphony.xwork2.conversion.impl.NumberConverter" scope="singleton"/>
+    <bean type="com.opensymphony.xwork2.conversion.TypeConverter" name="string" class="com.opensymphony.xwork2.conversion.impl.StringConverter" scope="singleton"/>
+
     <bean type="com.opensymphony.xwork2.TextProvider" name="xwork1" class="com.opensymphony.xwork2.TextProviderSupport" scope="default" />
     <bean type="com.opensymphony.xwork2.TextProvider" name="struts" class="com.opensymphony.xwork2.TextProviderSupport" scope="default" />
 

Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java (original)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/ObjectFactory.java Tue Mar  6 06:26:38 2012
@@ -259,15 +259,48 @@ public class ObjectFactory implements Se
 
     /**
      * Build converter of given type - it must be registered with {@link Container} first
-     * It's the first attempt to use Object Factory to build Converters, so the API can change in the future
-     * 
+     *
      * @param converterClass to instantiate
      * @return instance of converterClass with inject dependencies
      */
     public TypeConverter buildConverter(Class<? extends TypeConverter> converterClass) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Creating converter of type [#1]", converterClass.getCanonicalName());
+        }
         return container.getInstance(converterClass);
     }
 
+    /**
+     * Build converter of given type - it must be registered with {@link Container} first
+     *
+     * @param converterClass to instantiate
+     * @param name name of converter to use
+     * @return instance of converterClass with inject dependencies
+     */
+    public TypeConverter buildConverter(Class<? extends TypeConverter> converterClass, String name) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Creating converter of type [#1] with name [#2]", converterClass.getCanonicalName(), name);
+        }
+        return container.getInstance(converterClass, name);
+    }
+
+    /**
+     * Build converter of given type - it must be registered with {@link Container} first
+     *
+     * @param name name of converter to use
+     * @return instance of converterClass with inject dependencies
+     */
+    public TypeConverter buildConverter(String name) {
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Creating converter with name [#1]", name);
+        }
+        TypeConverter instance = container.getInstance(TypeConverter.class, name);
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Converter of Type [#1] with name [#2], created!", instance.getClass().getCanonicalName(),  name);
+        }
+        return instance;
+    }
+
     static class ContinuationsClassLoader extends ClassLoader {
         
     }

Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java (original)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/impl/DefaultConfiguration.java Tue Mar  6 06:26:38 2012
@@ -19,14 +19,34 @@ import com.opensymphony.xwork2.ActionCon
 import com.opensymphony.xwork2.DefaultTextProvider;
 import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.TextProvider;
-import com.opensymphony.xwork2.config.*;
-import com.opensymphony.xwork2.config.entities.*;
+import com.opensymphony.xwork2.config.Configuration;
+import com.opensymphony.xwork2.config.ConfigurationException;
+import com.opensymphony.xwork2.config.ConfigurationProvider;
+import com.opensymphony.xwork2.config.ContainerProvider;
+import com.opensymphony.xwork2.config.PackageProvider;
+import com.opensymphony.xwork2.config.RuntimeConfiguration;
+import com.opensymphony.xwork2.config.entities.ActionConfig;
+import com.opensymphony.xwork2.config.entities.InterceptorMapping;
+import com.opensymphony.xwork2.config.entities.PackageConfig;
+import com.opensymphony.xwork2.config.entities.ResultConfig;
+import com.opensymphony.xwork2.config.entities.ResultTypeConfig;
+import com.opensymphony.xwork2.config.entities.UnknownHandlerConfig;
 import com.opensymphony.xwork2.config.providers.InterceptorBuilder;
 import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
+import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
+import com.opensymphony.xwork2.conversion.impl.DateConverter;
 import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.impl.NumberConverter;
+import com.opensymphony.xwork2.conversion.impl.StringConverter;
 import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
-import com.opensymphony.xwork2.inject.*;
+import com.opensymphony.xwork2.inject.Container;
+import com.opensymphony.xwork2.inject.ContainerBuilder;
+import com.opensymphony.xwork2.inject.Context;
+import com.opensymphony.xwork2.inject.Factory;
+import com.opensymphony.xwork2.inject.Scope;
 import com.opensymphony.xwork2.ognl.OgnlReflectionProvider;
 import com.opensymphony.xwork2.ognl.OgnlUtil;
 import com.opensymphony.xwork2.ognl.OgnlValueStackFactory;
@@ -41,7 +61,13 @@ import com.opensymphony.xwork2.util.logg
 import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
 import ognl.PropertyAccessor;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
 
 
 /**
@@ -243,6 +269,11 @@ public class DefaultConfiguration implem
         builder.factory(ValueStackFactory.class, OgnlValueStackFactory.class, Scope.SINGLETON);
         builder.factory(XWorkConverter.class, Scope.SINGLETON);
         builder.factory(XWorkBasicConverter.class, Scope.SINGLETON);
+        builder.factory(TypeConverter.class, "collection",  CollectionConverter.class, Scope.SINGLETON);
+        builder.factory(TypeConverter.class, "array", ArrayConverter.class, Scope.SINGLETON);
+        builder.factory(TypeConverter.class, "date", DateConverter.class, Scope.SINGLETON);
+        builder.factory(TypeConverter.class, "number",  NumberConverter.class, Scope.SINGLETON);
+        builder.factory(TypeConverter.class, "string", StringConverter.class, Scope.SINGLETON);
         builder.factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON);
         builder.factory(ObjectTypeDeterminer.class, DefaultObjectTypeDeterminer.class, Scope.SINGLETON);
         builder.factory(PropertyAccessor.class, CompoundRoot.class.getName(), CompoundRootAccessor.class, Scope.SINGLETON);

Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java (original)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/config/providers/XWorkConfigurationProvider.java Tue Mar  6 06:26:38 2012
@@ -12,8 +12,14 @@ import com.opensymphony.xwork2.config.Co
 import com.opensymphony.xwork2.config.ConfigurationProvider;
 import com.opensymphony.xwork2.conversion.NullHandler;
 import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.conversion.impl.ArrayConverter;
+import com.opensymphony.xwork2.conversion.impl.CollectionConverter;
+import com.opensymphony.xwork2.conversion.impl.DateConverter;
 import com.opensymphony.xwork2.conversion.impl.DefaultObjectTypeDeterminer;
 import com.opensymphony.xwork2.conversion.impl.InstantiatingNullHandler;
+import com.opensymphony.xwork2.conversion.impl.NumberConverter;
+import com.opensymphony.xwork2.conversion.impl.StringConverter;
 import com.opensymphony.xwork2.conversion.impl.XWorkBasicConverter;
 import com.opensymphony.xwork2.conversion.impl.XWorkConverter;
 import com.opensymphony.xwork2.inject.ContainerBuilder;
@@ -111,7 +117,12 @@ public class XWorkConfigurationProvider 
                 .factory(TextProvider.class, "system", DefaultTextProvider.class, Scope.SINGLETON)
                 .factory(TextProvider.class, TextProviderSupport.class, Scope.SINGLETON)
                 .factory(OgnlUtil.class, Scope.SINGLETON)
-                .factory(XWorkBasicConverter.class, Scope.SINGLETON);
+                .factory(XWorkBasicConverter.class, Scope.SINGLETON)
+                .factory(TypeConverter.class, "collection", CollectionConverter.class, Scope.SINGLETON)
+                .factory(TypeConverter.class, "array", ArrayConverter.class, Scope.SINGLETON)
+                .factory(TypeConverter.class, "date", DateConverter.class, Scope.SINGLETON)
+                .factory(TypeConverter.class, "number", NumberConverter.class, Scope.SINGLETON)
+                .factory(TypeConverter.class, "string", StringConverter.class, Scope.SINGLETON);
         props.setProperty("devMode", Boolean.FALSE.toString());
         props.setProperty("logMissingProperties", Boolean.FALSE.toString());
         props.setProperty("enableOGNLExpressionCache", Boolean.TRUE.toString());

Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/ArrayConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/ArrayConverter.java?rev=1297347&view=auto
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/ArrayConverter.java (added)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/ArrayConverter.java Tue Mar  6 06:26:38 2012
@@ -0,0 +1,36 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.conversion.TypeConverter;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Member;
+import java.util.Map;
+
+public class ArrayConverter extends DefaultTypeConverter {
+
+    @Override
+    public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
+        Object result = null;
+        Class componentType = toType.getComponentType();
+
+        if (componentType != null) {
+            TypeConverter converter = getTypeConverter(context);
+
+            if (value.getClass().isArray()) {
+                int length = Array.getLength(value);
+                result = Array.newInstance(componentType, length);
+
+                for (int i = 0; i < length; i++) {
+                    Object valueItem = Array.get(value, i);
+                    Array.set(result, i, converter.convertValue(context, target, member, propertyName, valueItem, componentType));
+                }
+            } else {
+                result = Array.newInstance(componentType, 1);
+                Array.set(result, 0, converter.convertValue(context, target, member, propertyName, value, componentType));
+            }
+        }
+
+        return result;
+    }
+
+}

Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/CollectionConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/CollectionConverter.java?rev=1297347&view=auto
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/CollectionConverter.java (added)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/CollectionConverter.java Tue Mar  6 06:26:38 2012
@@ -0,0 +1,101 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.ObjectFactory;
+import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
+import com.opensymphony.xwork2.conversion.TypeConverter;
+import com.opensymphony.xwork2.inject.Inject;
+import com.opensymphony.xwork2.util.XWorkList;
+
+import java.lang.reflect.Member;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+public class CollectionConverter extends DefaultTypeConverter {
+
+    private ObjectTypeDeterminer objectTypeDeterminer;
+    private ObjectFactory objectFactory;
+
+    @Inject
+    public void setObjectTypeDeterminer(ObjectTypeDeterminer determiner) {
+        this.objectTypeDeterminer = determiner;
+    }
+
+    @Inject
+    public void setObjectFactory(ObjectFactory factory) {
+        this.objectFactory = factory;
+    }
+
+    public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
+        Collection result;
+        Class memberType = String.class;
+
+        if (target != null) {
+            //memberType = (Class) XWorkConverter.getInstance().getConverter(o.getClass(), XWorkConverter.CONVERSION_COLLECTION_PREFIX + prop);
+            memberType = objectTypeDeterminer.getElementClass(target.getClass(), propertyName, null);
+
+            if (memberType == null) {
+                memberType = String.class;
+            }
+        }
+
+        if (toType.isAssignableFrom(value.getClass())) {
+            // no need to do anything
+            result = (Collection) value;
+        } else if (value.getClass().isArray()) {
+            Object[] objArray = (Object[]) value;
+            TypeConverter converter = getTypeConverter(context);
+            result = createCollection(toType, memberType, objArray.length);
+
+            for (Object anObjArray : objArray) {
+                Object convertedValue = converter.convertValue(context, target, member, propertyName, anObjArray, memberType);
+                if (!TypeConverter.NO_CONVERSION_POSSIBLE.equals(convertedValue)) {
+                    result.add(convertedValue);
+                }
+            }
+        } else if (Collection.class.isAssignableFrom(value.getClass())) {
+            Collection col = (Collection) value;
+            TypeConverter converter = getTypeConverter(context);
+            result = createCollection(toType, memberType, col.size());
+
+            for (Object aCol : col) {
+                Object convertedValue = converter.convertValue(context, target, member, propertyName, aCol, memberType);
+                if (!TypeConverter.NO_CONVERSION_POSSIBLE.equals(convertedValue)) {
+                    result.add(convertedValue);
+                }
+            }
+        } else {
+            result = createCollection(toType, memberType, -1);
+            result.add(value);
+        }
+
+        return result;
+
+    }
+
+    private Collection createCollection(Class toType, Class memberType, int size) {
+        Collection result;
+
+        if (toType == Set.class) {
+            if (size > 0) {
+                result = new HashSet(size);
+            } else {
+                result = new HashSet();
+            }
+        } else if (toType == SortedSet.class) {
+            result = new TreeSet();
+        } else {
+            if (size > 0) {
+                result = new XWorkList(objectFactory, memberType, size);
+            } else {
+                result = new XWorkList(objectFactory, memberType);
+            }
+        }
+
+        return result;
+    }
+
+}

Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java?rev=1297347&view=auto
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java (added)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DateConverter.java Tue Mar  6 06:26:38 2012
@@ -0,0 +1,101 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.XWorkException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Member;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+public class DateConverter extends DefaultTypeConverter {
+
+    @Override
+    public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
+        Date result = null;
+
+        if (value instanceof String && value != null && ((String) value).length() > 0) {
+            String sa = (String) value;
+            Locale locale = getLocale(context);
+
+            DateFormat df = null;
+            if (java.sql.Time.class == toType) {
+                df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
+            } else if (java.sql.Timestamp.class == toType) {
+                Date check = null;
+                SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
+                        DateFormat.MEDIUM,
+                        locale);
+                SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,
+                        locale);
+
+                SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
+                        locale);
+
+                SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};
+                for (SimpleDateFormat fmt : fmts) {
+                    try {
+                        check = fmt.parse(sa);
+                        df = fmt;
+                        if (check != null) {
+                            break;
+                        }
+                    } catch (ParseException ignore) {
+                    }
+                }
+            } else if (java.util.Date.class == toType) {
+                Date check;
+                DateFormat[] dfs = getDateFormats(locale);
+                for (DateFormat df1 : dfs) {
+                    try {
+                        check = df1.parse(sa);
+                        df = df1;
+                        if (check != null) {
+                            break;
+                        }
+                    } catch (ParseException ignore) {
+                    }
+                }
+            }
+            //final fallback for dates without time
+            if (df == null) {
+                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+            }
+            try {
+                df.setLenient(false); // let's use strict parsing (XW-341)
+                result = df.parse(sa);
+                if (!(Date.class == toType)) {
+                    try {
+                        Constructor constructor = toType.getConstructor(new Class[]{long.class});
+                        return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
+                    } catch (Exception e) {
+                        throw new XWorkException("Couldn't create class " + toType + " using default (long) constructor", e);
+                    }
+                }
+            } catch (ParseException e) {
+                throw new XWorkException("Could not parse date", e);
+            }
+        } else if (Date.class.isAssignableFrom(value.getClass())) {
+            result = (Date) value;
+        }
+        return result;
+    }
+
+    private DateFormat[] getDateFormats(Locale locale) {
+        DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
+        DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
+        DateFormat dt3 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
+
+        DateFormat d1 = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+        DateFormat d2 = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
+        DateFormat d3 = DateFormat.getDateInstance(DateFormat.LONG, locale);
+
+        DateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+
+        return new DateFormat[]{dt1, dt2, dt3, rfc3399, d1, d2, d3};
+    }
+
+}

Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverter.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverter.java (original)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/DefaultTypeConverter.java Tue Mar  6 06:26:38 2012
@@ -30,6 +30,7 @@
 //--------------------------------------------------------------------------
 package com.opensymphony.xwork2.conversion.impl;
 
+import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.conversion.TypeConverter;
 import com.opensymphony.xwork2.ognl.XWorkTypeConverterWrapper;
 
@@ -39,6 +40,7 @@ import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -49,6 +51,9 @@ import java.util.Map;
  * @author Drew Davidson (drew@ognl.org)
  */
 public class DefaultTypeConverter implements TypeConverter {
+
+    protected static String MILLISECOND_FORMAT = ".SSS";
+
     private static final String NULL_STRING = "null";
 
     private final Map<Class, Object> primitiveDefaults;
@@ -325,4 +330,16 @@ public class DefaultTypeConverter implem
     public static String stringValue(Object value) {
         return stringValue(value, false);
     }
+
+    protected Locale getLocale(Map<String, Object> context) {
+        if (context == null) {
+            return Locale.getDefault();
+        }
+        Locale locale = (Locale) context.get(ActionContext.LOCALE);
+        if (locale == null) {
+            locale = Locale.getDefault();
+        }
+        return locale;
+    }
+
 }

Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java?rev=1297347&view=auto
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java (added)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java Tue Mar  6 06:26:38 2012
@@ -0,0 +1,116 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import com.opensymphony.xwork2.XWorkException;
+
+import java.lang.reflect.Member;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Map;
+
+public class NumberConverter extends DefaultTypeConverter {
+
+    public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
+        if (value instanceof String) {
+            if (toType == BigDecimal.class) {
+                return new BigDecimal((String) value);
+            } else if (toType == BigInteger.class) {
+                return new BigInteger((String) value);
+            } else if (toType.isPrimitive()) {
+                Object convertedValue = super.convertValue(context, value, toType);
+                String stringValue = (String) value;
+                if (!isInRange((Number) convertedValue, stringValue, toType))
+                    throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + convertedValue.getClass().getName());
+
+                return convertedValue;
+            } else {
+                String stringValue = (String) value;
+                if (!toType.isPrimitive() && (stringValue == null || stringValue.length() == 0)) {
+                    return null;
+                }
+                NumberFormat numFormat = NumberFormat.getInstance(getLocale(context));
+                ParsePosition parsePos = new ParsePosition(0);
+                if (isIntegerType(toType)) {
+                    numFormat.setParseIntegerOnly(true);
+                }
+                numFormat.setGroupingUsed(true);
+                Number number = numFormat.parse(stringValue, parsePos);
+
+                if (parsePos.getIndex() != stringValue.length()) {
+                    throw new XWorkException("Unparseable number: \"" + stringValue + "\" at position "
+                            + parsePos.getIndex());
+                } else {
+                    if (!isInRange(number, stringValue, toType))
+                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + number.getClass().getName());
+
+                    value = super.convertValue(context, number, toType);
+                }
+            }
+        } else if (value instanceof Object[]) {
+            Object[] objArray = (Object[]) value;
+
+            if (objArray.length == 1) {
+                return convertValue(context, null, null, null, objArray[0], toType);
+            }
+        }
+
+        // pass it through DefaultTypeConverter
+        return super.convertValue(context, value, toType);
+    }
+
+    protected boolean isInRange(Number value, String stringValue, Class toType) {
+        Number bigValue = null;
+        Number lowerBound = null;
+        Number upperBound = null;
+
+        try {
+            if (double.class == toType || Double.class == toType) {
+                bigValue = new BigDecimal(stringValue);
+                // Double.MIN_VALUE is the smallest positive non-zero number
+                lowerBound = BigDecimal.valueOf(Double.MAX_VALUE).negate();
+                upperBound = BigDecimal.valueOf(Double.MAX_VALUE);
+            } else if (float.class == toType || Float.class == toType) {
+                bigValue = new BigDecimal(stringValue);
+                // Float.MIN_VALUE is the smallest positive non-zero number
+                lowerBound = BigDecimal.valueOf(Float.MAX_VALUE).negate();
+                upperBound = BigDecimal.valueOf(Float.MAX_VALUE);
+            } else if (byte.class == toType || Byte.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Byte.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Byte.MAX_VALUE);
+            } else if (char.class == toType || Character.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Character.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Character.MAX_VALUE);
+            } else if (short.class == toType || Short.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Short.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Short.MAX_VALUE);
+            } else if (int.class == toType || Integer.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Integer.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Integer.MAX_VALUE);
+            } else if (long.class == toType || Long.class == toType) {
+                bigValue = new BigInteger(stringValue);
+                lowerBound = BigInteger.valueOf(Long.MIN_VALUE);
+                upperBound = BigInteger.valueOf(Long.MAX_VALUE);
+            }
+        } catch (NumberFormatException e) {
+            //shoult it fail here? BigInteger doesnt seem to be so nice parsing numbers as NumberFormat
+            return true;
+        }
+
+        return ((Comparable)bigValue).compareTo(lowerBound) >= 0 && ((Comparable)bigValue).compareTo(upperBound) <= 0;
+    }
+
+    private boolean isIntegerType(Class type) {
+        if (double.class == type || float.class == type || Double.class == type || Float.class == type
+                || char.class == type || Character.class == type) {
+            return false;
+        }
+
+        return true;
+    }
+
+}

Added: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/StringConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/StringConverter.java?rev=1297347&view=auto
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/StringConverter.java (added)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/StringConverter.java Tue Mar  6 06:26:38 2012
@@ -0,0 +1,73 @@
+package com.opensymphony.xwork2.conversion.impl;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Member;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+public class StringConverter extends DefaultTypeConverter {
+
+    @Override
+    public Object convertValue(Map<String, Object> context, Object target, Member member, String propertyName, Object value, Class toType) {
+        String result = null;
+
+        if (value instanceof int[]) {
+            int[] x = (int[]) value;
+            List<Integer> intArray = new ArrayList<Integer>(x.length);
+
+            for (int aX : x) {
+                intArray.add(Integer.valueOf(aX));
+            }
+
+            result = StringUtils.join(intArray, ", ");
+        } else if (value instanceof long[]) {
+            long[] x = (long[]) value;
+            List<Long> longArray = new ArrayList<Long>(x.length);
+
+            for (long aX : x) {
+                longArray.add(Long.valueOf(aX));
+            }
+
+            result = StringUtils.join(longArray, ", ");
+        } else if (value instanceof double[]) {
+            double[] x = (double[]) value;
+            List<Double> doubleArray = new ArrayList<Double>(x.length);
+
+            for (double aX : x) {
+                doubleArray.add(new Double(aX));
+            }
+
+            result = StringUtils.join(doubleArray, ", ");
+        } else if (value instanceof boolean[]) {
+            boolean[] x = (boolean[]) value;
+            List<Boolean> booleanArray = new ArrayList<Boolean>(x.length);
+
+            for (boolean aX : x) {
+                booleanArray.add(new Boolean(aX));
+            }
+
+            result = StringUtils.join(booleanArray, ", ");
+        } else if (value instanceof Date) {
+            DateFormat df = null;
+            if (value instanceof java.sql.Time) {
+                df = DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale(context));
+            } else if (value instanceof java.sql.Timestamp) {
+                SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
+                        DateFormat.MEDIUM,
+                        getLocale(context));
+                df = new SimpleDateFormat(dfmt.toPattern() + MILLISECOND_FORMAT);
+            } else {
+                df = DateFormat.getDateInstance(DateFormat.SHORT, getLocale(context));
+            }
+            result = df.format(value);
+        } else if (value instanceof String[]) {
+            result = StringUtils.join((String[]) value, ", ");
+        }
+        return result;
+    }
+}

Modified: struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java (original)
+++ struts/struts2/trunk/xwork-core/src/main/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverter.java Tue Mar  6 06:26:38 2012
@@ -15,36 +15,16 @@
  */
 package com.opensymphony.xwork2.conversion.impl;
 
-import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.ObjectFactory;
 import com.opensymphony.xwork2.XWorkException;
-import com.opensymphony.xwork2.conversion.ObjectTypeDeterminer;
 import com.opensymphony.xwork2.conversion.TypeConverter;
 import com.opensymphony.xwork2.inject.Inject;
-import com.opensymphony.xwork2.util.XWorkList;
-import org.apache.commons.lang3.StringUtils;
 
-import java.lang.reflect.Array;
-import java.lang.reflect.Constructor;
 import java.lang.reflect.Member;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.text.DateFormat;
-import java.text.NumberFormat;
-import java.text.ParseException;
-import java.text.ParsePosition;
-import java.text.SimpleDateFormat;
-import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
 import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Locale;
 import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
 
 
 /**
@@ -65,7 +45,19 @@ import java.util.TreeSet;
  * </ul>
  * <p/> Note that with arrays the type conversion will defer to the type of the array elements and try to convert each
  * item individually. As with any other type conversion, if the conversion can't be performed the standard type
- * conversion error reporting is used to indicate a problem occured while processing the type conversion.
+ * conversion error reporting is used to indicate a problem occurred while processing the type conversion.
+ * <p/> As from version 2.3.2 you can override default converters by implementting {@link TypeConverter} interface
+ * and specifying beans in struts.xml as follow:
+ * &lt;bean type=&quot;com.opensymphony.xwork2.conversion.TypeConverter&quot; name=&quot;collection&quot; class="com.application.MyCollectionConverter&quot; scope=&quot;singleton&quot;/&gt;
+ * <p/>
+ * There are five types of converters defined:
+ * <ul>
+ * <li>collection</li>
+ * <li>array</li>
+ * <li>date</li>
+ * <li>number</li>
+ * <li>string</li>
+ * </ul>
  * <p/>
  * <!-- END SNIPPET: javadoc -->
  *
@@ -76,23 +68,15 @@ import java.util.TreeSet;
  */
 public class XWorkBasicConverter extends DefaultTypeConverter {
 
-    private static String MILLISECOND_FORMAT = ".SSS";
-    
-    private ObjectTypeDeterminer objectTypeDeterminer;
     private ObjectFactory objectFactory;
 
     @Inject
-    public void setObjectTypeDeterminer(ObjectTypeDeterminer det) {
-        this.objectTypeDeterminer = det;
-    }
-    
-    @Inject
     public void setObjectFactory(ObjectFactory fac) {
         this.objectFactory = fac;
     }
 
     @Override
-    public Object convertValue(Map<String, Object> context, Object o, Member member, String s, Object value, Class toType) {
+    public Object convertValue(Map<String, Object> context, Object o, Member member, String propertyName, Object value, Class toType) {
         Object result = null;
 
         if (value == null || toType.isAssignableFrom(value.getClass())) {
@@ -117,18 +101,13 @@ public class XWorkBasicConverter extends
         } else if (toType == Boolean.class) {
             result = doConvertToBoolean(value);
         } else if (toType.isArray()) {
-            result = doConvertToArray(context, o, member, s, value, toType);
+            result = doConvertToArray(context, o, member, propertyName, value, toType);
         } else if (Date.class.isAssignableFrom(toType)) {
             result = doConvertToDate(context, value, toType);
         } else if (Calendar.class.isAssignableFrom(toType)) {
-            Date dateResult = (Date) doConvertToDate(context, value, Date.class);
-            if (dateResult != null) {
-                Calendar calendar = Calendar.getInstance();
-                calendar.setTime(dateResult);
-                result = calendar;
-            } 
+            result = doConvertToCalendar(context, value);
         } else if (Collection.class.isAssignableFrom(toType)) {
-            result = doConvertToCollection(context, o, member, s, value, toType);
+            result = doConvertToCollection(context, o, member, propertyName, value, toType);
         } else if (toType == Character.class) {
             result = doConvertToCharacter(value);
         } else if (toType == char.class) {
@@ -150,7 +129,7 @@ public class XWorkBasicConverter extends
                 }
 
                 // let's try to convert the first element only
-                result = convertValue(context, o, member, s, value, toType);
+                result = convertValue(context, o, member, propertyName, value, toType);
             } else if (!"".equals(value)) { // we've already tried the types we know
                 result = super.convertValue(context, value, toType);
             }
@@ -163,110 +142,43 @@ public class XWorkBasicConverter extends
         return result;
     }
 
-    private Locale getLocale(Map<String, Object> context) {
-        if (context == null) {
-            return Locale.getDefault();
-        }
-
-        Locale locale = (Locale) context.get(ActionContext.LOCALE);
-
-        if (locale == null) {
-            locale = Locale.getDefault();
-        }
-
-        return locale;
-    }
-
-    /**
-     * Creates a Collection of the specified type.
-     *
-     * @param fromObject
-     * @param propertyName
-     * @param toType       the type of Collection to create
-     * @param memberType   the type of object elements in this collection must be
-     * @param size         the initial size of the collection (ignored if 0 or less)
-     * @return a Collection of the specified type
-     */
-    private Collection createCollection(Object fromObject, String propertyName, Class toType, Class memberType, int size) {
-//        try {
-//            Object original = Ognl.getValue(OgnlUtil.compile(propertyName),fromObject);
-//            if (original instanceof Collection) {
-//                Collection coll = (Collection) original;
-//                coll.clear();
-//                return coll;
-//            }
-//        } catch (Exception e) {
-//            // fail back to creating a new one
-//        }
-
-        Collection result;
-
-        if (toType == Set.class) {
-            if (size > 0) {
-                result = new HashSet(size);
-            } else {
-                result = new HashSet();
-            }
-        } else if (toType == SortedSet.class) {
-            result = new TreeSet();
-        } else {
-            if (size > 0) {
-                result = new XWorkList(objectFactory, memberType, size);
-            } else {
-                result = new XWorkList(objectFactory, memberType);
-            }
+    private Object doConvertToCalendar(Map<String, Object> context, Object value) {
+        Object result = null;
+        Date dateResult = (Date) doConvertToDate(context, value, Date.class);
+        if (dateResult != null) {
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(dateResult);
+            result = calendar;
         }
-
         return result;
     }
 
-    private Object doConvertToArray(Map<String, Object> context, Object o, Member member, String s, Object value, Class toType) {
-        Object result = null;
-        Class componentType = toType.getComponentType();
-
-        if (componentType != null) {
-            TypeConverter converter = getTypeConverter(context);
-
-            if (value.getClass().isArray()) {
-                int length = Array.getLength(value);
-                result = Array.newInstance(componentType, length);
-
-                for (int i = 0; i < length; i++) {
-                    Object valueItem = Array.get(value, i);
-                    Array.set(result, i, converter.convertValue(context, o, member, s, valueItem, componentType));
-                }
-            } else {
-                result = Array.newInstance(componentType, 1);
-                Array.set(result, 0, converter.convertValue(context, o, member, s, value, componentType));
-            }
+    private Object doConvertToArray(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
+        TypeConverter converter = objectFactory.buildConverter("array");
+        if (converter == null) {
+            throw new XWorkException("TypeConverter with name [array] must be registered first!");
         }
-
-        return result;
+        return converter.convertValue(context, o, member, prop, value, toType);
     }
 
     private Object doConvertToCharacter(Object value) {
         if (value instanceof String) {
             String cStr = (String) value;
-
             return (cStr.length() > 0) ? new Character(cStr.charAt(0)) : null;
         }
-
         return null;
     }
 
     private Object doConvertToBoolean(Object value) {
         if (value instanceof String) {
             String bStr = (String) value;
-
             return Boolean.valueOf(bStr);
         }
-
         return null;
     }
 
     private Class doConvertToClass(Object value) {
         Class clazz = null;
-
         if (value instanceof String && value != null && ((String) value).length() > 0) {
             try {
                 clazz = Class.forName((String) value);
@@ -274,317 +186,38 @@ public class XWorkBasicConverter extends
                 throw new XWorkException(e.getLocalizedMessage(), e);
             }
         }
-
         return clazz;
     }
 
-    private Collection doConvertToCollection(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
-        Collection result;
-        Class memberType = String.class;
-
-        if (o != null) {
-            //memberType = (Class) XWorkConverter.getInstance().getConverter(o.getClass(), XWorkConverter.CONVERSION_COLLECTION_PREFIX + prop);
-            memberType = objectTypeDeterminer.getElementClass(o.getClass(), prop, null);
-
-            if (memberType == null) {
-                memberType = String.class;
-            }
+    private Object doConvertToCollection(Map<String, Object> context, Object o, Member member, String prop, Object value, Class toType) {
+        TypeConverter converter = objectFactory.buildConverter("collection");
+        if (converter == null) {
+            throw new XWorkException("TypeConverter with name [collection] must be registered first!");
         }
-
-        if (toType.isAssignableFrom(value.getClass())) {
-            // no need to do anything
-            result = (Collection) value;
-        } else if (value.getClass().isArray()) {
-            Object[] objArray = (Object[]) value;
-            TypeConverter converter = getTypeConverter(context);
-            result = createCollection(o, prop, toType, memberType, objArray.length);
-
-            for (Object anObjArray : objArray) {
-                result.add(converter.convertValue(context, o, member, prop, anObjArray, memberType));
-            }
-        } else if (Collection.class.isAssignableFrom(value.getClass())) {
-            Collection col = (Collection) value;
-            TypeConverter converter = getTypeConverter(context);
-            result = createCollection(o, prop, toType, memberType, col.size());
-
-            for (Object aCol : col) {
-                result.add(converter.convertValue(context, o, member, prop, aCol, memberType));
-            }
-        } else {
-            result = createCollection(o, prop, toType, memberType, -1);
-            result.add(value);
-        }
-
-        return result;
+        return converter.convertValue(context, o, member, prop, value, toType);
     }
 
     private Object doConvertToDate(Map<String, Object> context, Object value, Class toType) {
-        Date result = null;
-
-        if (value instanceof String && value != null && ((String) value).length() > 0) {
-            String sa = (String) value;
-            Locale locale = getLocale(context);
-
-            DateFormat df = null;
-            if (java.sql.Time.class == toType) {
-                df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
-            } else if (java.sql.Timestamp.class == toType) {
-                Date check = null;
-                SimpleDateFormat dtfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
-                        DateFormat.MEDIUM,
-                        locale);
-                SimpleDateFormat fullfmt = new SimpleDateFormat(dtfmt.toPattern() + MILLISECOND_FORMAT,
-                        locale);
-
-                SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateInstance(DateFormat.SHORT,
-                        locale);
-
-                SimpleDateFormat[] fmts = {fullfmt, dtfmt, dfmt};
-                for (SimpleDateFormat fmt : fmts) {
-                    try {
-                        check = fmt.parse(sa);
-                        df = fmt;
-                        if (check != null) {
-                            break;
-                        }
-                    } catch (ParseException ignore) {
-                    }
-                }
-            } else if (java.util.Date.class == toType) {
-                Date check = null;
-                DateFormat[] dfs = getDateFormats(locale);
-                for (DateFormat df1 : dfs) {
-                    try {
-                        check = df1.parse(sa);
-                        df = df1;
-                        if (check != null) {
-                            break;
-                        }
-                    }
-                    catch (ParseException ignore) {
-                    }
-                }
-            }
-            //final fallback for dates without time
-            if (df == null) {
-                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
-            }
-            try {
-                df.setLenient(false); // let's use strict parsing (XW-341)
-                result = df.parse(sa);
-                if (!(Date.class == toType)) {
-                    try {
-                        Constructor constructor = toType.getConstructor(new Class[]{long.class});
-                        return constructor.newInstance(new Object[]{Long.valueOf(result.getTime())});
-                    } catch (Exception e) {
-                        throw new XWorkException("Couldn't create class " + toType + " using default (long) constructor", e);
-                    }
-                }
-            } catch (ParseException e) {
-                throw new XWorkException("Could not parse date", e);
-            }
-        } else if (Date.class.isAssignableFrom(value.getClass())) {
-            result = (Date) value;
+        TypeConverter converter = objectFactory.buildConverter("date");
+        if (converter == null) {
+            throw new XWorkException("TypeConverter with name [date] must be registered first!");
         }
-        return result;
-    }
-
-    private DateFormat[] getDateFormats(Locale locale) {
-        DateFormat dt1 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
-        DateFormat dt2 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
-        DateFormat dt3 = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
-
-        DateFormat d1 = DateFormat.getDateInstance(DateFormat.SHORT, locale);
-        DateFormat d2 = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
-        DateFormat d3 = DateFormat.getDateInstance(DateFormat.LONG, locale);
-
-        DateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
-
-        DateFormat[] dfs = {dt1, dt2, dt3, rfc3399, d1, d2, d3}; //added RFC 3339 date format (XW-473)
-        return dfs;
+        return converter.convertValue(context, null, null, null, value, toType);
     }
 
     private Object doConvertToNumber(Map<String, Object> context, Object value, Class toType) {
-        if (value instanceof String) {
-            if (toType == BigDecimal.class) {
-                return new BigDecimal((String) value);
-            } else if (toType == BigInteger.class) {
-                return new BigInteger((String) value);
-            } else if (toType.isPrimitive()) {
-                Object convertedValue = super.convertValue(context, value, toType);
-                String stringValue = (String) value;
-                if (!isInRange((Number)convertedValue, stringValue,  toType))
-                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + convertedValue.getClass().getName());
-
-                return convertedValue;
-            } else {
-                String stringValue = (String) value;
-                if (!toType.isPrimitive() && (stringValue == null || stringValue.length() == 0)) {
-                    return null;
-                }
-                NumberFormat numFormat = NumberFormat.getInstance(getLocale(context));
-                ParsePosition parsePos = new ParsePosition(0);
-                if (isIntegerType(toType)) {
-                    numFormat.setParseIntegerOnly(true);
-                }
-                numFormat.setGroupingUsed(true);
-                Number number = numFormat.parse(stringValue, parsePos);
-
-                if (parsePos.getIndex() != stringValue.length()) {
-                    throw new XWorkException("Unparseable number: \"" + stringValue + "\" at position "
-                            + parsePos.getIndex());
-                } else {
-                    if (!isInRange(number, stringValue,  toType))
-                        throw new XWorkException("Overflow or underflow casting: \"" + stringValue + "\" into class " + number.getClass().getName());
-                    
-                    value = super.convertValue(context, number, toType);
-                }
-            }
-        } else if (value instanceof Object[]) {
-            Object[] objArray = (Object[]) value;
-
-            if (objArray.length == 1) {
-                return doConvertToNumber(context, objArray[0], toType);
-            }
+        TypeConverter converter = objectFactory.buildConverter("number");
+        if (converter == null) {
+            throw new XWorkException("TypeConverter with name [number] must be registered first!");
         }
-
-        // pass it through DefaultTypeConverter
-        return super.convertValue(context, value, toType);
+        return converter.convertValue(context, null, null, null, value, toType);
     }
 
-    protected boolean isInRange(Number value, String stringValue, Class toType) {
-        Number bigValue = null;
-        Number lowerBound = null;
-        Number upperBound = null;
-
-        try {
-            if (double.class == toType || Double.class == toType) {
-                bigValue = new BigDecimal(stringValue);
-                // Double.MIN_VALUE is the smallest positive non-zero number
-                lowerBound = BigDecimal.valueOf(Double.MAX_VALUE).negate();
-                upperBound = BigDecimal.valueOf(Double.MAX_VALUE);
-            } else if (float.class == toType || Float.class == toType) {
-                bigValue = new BigDecimal(stringValue);
-                // Float.MIN_VALUE is the smallest positive non-zero number
-                lowerBound = BigDecimal.valueOf(Float.MAX_VALUE).negate();
-                upperBound = BigDecimal.valueOf(Float.MAX_VALUE);
-            } else if (byte.class == toType || Byte.class == toType) {
-                bigValue = new BigInteger(stringValue);
-                lowerBound = BigInteger.valueOf(Byte.MIN_VALUE);
-                upperBound = BigInteger.valueOf(Byte.MAX_VALUE);
-            } else if (char.class == toType || Character.class == toType) {
-                bigValue = new BigInteger(stringValue);
-                lowerBound = BigInteger.valueOf(Character.MIN_VALUE);
-                upperBound = BigInteger.valueOf(Character.MAX_VALUE);
-            } else if (short.class == toType || Short.class == toType) {
-                bigValue = new BigInteger(stringValue);
-                lowerBound = BigInteger.valueOf(Short.MIN_VALUE);
-                upperBound = BigInteger.valueOf(Short.MAX_VALUE);
-            } else if (int.class == toType || Integer.class == toType) {
-                bigValue = new BigInteger(stringValue);
-                lowerBound = BigInteger.valueOf(Integer.MIN_VALUE);
-                upperBound = BigInteger.valueOf(Integer.MAX_VALUE);
-            } else if (long.class == toType || Long.class == toType) {
-                bigValue = new BigInteger(stringValue);
-                lowerBound = BigInteger.valueOf(Long.MIN_VALUE);
-                upperBound = BigInteger.valueOf(Long.MAX_VALUE);
-            }
-        } catch (NumberFormatException e) {
-            //shoult it fail here? BigInteger doesnt seem to be so nice parsing numbers as NumberFormat
-            return true;
-        }
-
-        return ((Comparable)bigValue).compareTo(lowerBound) >= 0 && ((Comparable)bigValue).compareTo(upperBound) <= 0;
-    }
-
-    protected boolean isIntegerType(Class type) {
-        if (double.class == type || float.class == type || Double.class == type || Float.class == type
-                || char.class == type || Character.class == type) {
-            return false;
+    private Object doConvertToString(Map<String, Object> context, Object value) {
+        TypeConverter converter = objectFactory.buildConverter("string");
+        if (converter == null) {
+            throw new XWorkException("TypeConverter with name [string] must be registered first!");
         }
-
-        return true;
-    }
-
-    /**
-     * Converts the input as a number using java's number formatter to a string output.
-     */
-    private String doConvertFromNumberToString(Map<String, Object> context, Object value, Class toType) {
-        // XW-409: If the input is a Number we should format it to a string using the choosen locale and use java's numberformatter
-        if (Number.class.isAssignableFrom(toType)) {
-            NumberFormat numFormat = NumberFormat.getInstance(getLocale(context));
-            if (isIntegerType(toType)) {
-                numFormat.setParseIntegerOnly(true);
-            }
-            numFormat.setGroupingUsed(true);
-            numFormat.setMaximumFractionDigits(99); // to be sure we include all digits after decimal seperator, otherwise some of the fractions can be chopped
-
-            String number = numFormat.format(value);
-            if (number != null) {
-                return number;
-            }
-        }
-
-        return null; // no number
-    }
-
-
-    private String doConvertToString(Map<String, Object> context, Object value) {
-        String result = null;
-
-        if (value instanceof int[]) {
-            int[] x = (int[]) value;
-            List<Integer> intArray = new ArrayList<Integer>(x.length);
-
-            for (int aX : x) {
-                intArray.add(Integer.valueOf(aX));
-            }
-
-            result = StringUtils.join(intArray, ", ");
-        } else if (value instanceof long[]) {
-            long[] x = (long[]) value;
-            List<Long> longArray = new ArrayList<Long>(x.length);
-
-            for (long aX : x) {
-                longArray.add(Long.valueOf(aX));
-            }
-
-            result = StringUtils.join(longArray, ", ");
-        } else if (value instanceof double[]) {
-            double[] x = (double[]) value;
-            List<Double> doubleArray = new ArrayList<Double>(x.length);
-
-            for (double aX : x) {
-                doubleArray.add(new Double(aX));
-            }
-
-            result = StringUtils.join(doubleArray, ", ");
-        } else if (value instanceof boolean[]) {
-            boolean[] x = (boolean[]) value;
-            List<Boolean> booleanArray = new ArrayList<Boolean>(x.length);
-
-            for (boolean aX : x) {
-                booleanArray.add(new Boolean(aX));
-            }
-
-            result = StringUtils.join(booleanArray, ", ");
-        } else if (value instanceof Date) {
-            DateFormat df = null;
-            if (value instanceof java.sql.Time) {
-                df = DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale(context));
-            } else if (value instanceof java.sql.Timestamp) {
-                SimpleDateFormat dfmt = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT,
-                        DateFormat.MEDIUM,
-                        getLocale(context));
-                df = new SimpleDateFormat(dfmt.toPattern() + MILLISECOND_FORMAT);
-            } else {
-                df = DateFormat.getDateInstance(DateFormat.SHORT, getLocale(context));
-            }
-            result = df.format(value);
-        } else if (value instanceof String[]) {
-            result = StringUtils.join((String[]) value, ", ");
-        }
-
-        return result;
+        return converter.convertValue(context, null, null, null, value, null);
     }
 }

Modified: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java (original)
+++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkBasicConverterTest.java Tue Mar  6 06:26:38 2012
@@ -17,12 +17,16 @@ package com.opensymphony.xwork2.conversi
 
 import com.opensymphony.xwork2.ActionContext;
 import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.XWorkTestCase;
 import com.opensymphony.xwork2.test.annotations.Person;
-import junit.framework.TestCase;
 
-import java.text.DateFormat;
-import java.util.*;
 import java.lang.reflect.Member;
+import java.text.DateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
 
 /**
  * Test case for XWorkBasicConverter
@@ -30,7 +34,9 @@ import java.lang.reflect.Member;
  * @author tm_jee
  * @version $Date$ $Id$
  */
-public class XWorkBasicConverterTest extends TestCase {
+public class XWorkBasicConverterTest extends XWorkTestCase {
+
+    private XWorkBasicConverter basicConverter;
 
     // TODO: test for every possible conversion
     // take into account of empty string
@@ -38,14 +44,12 @@ public class XWorkBasicConverterTest ext
     // object -> return null when empty string is passed
 
     public void testDateConversionWithEmptyValue() {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "", Date.class);
         // we must not get XWorkException as that will caused a conversion error
         assertNull(convertedObject);
     }
 
     public void testDateConversionWithInvalidValue() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         try {
             Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, "asdsd", Date.class);
             fail("XWorkException expected - conversion error occurred");
@@ -55,7 +59,6 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testDateWithLocalePoland() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
 
         Map<String, Object> map = new HashMap<String, Object>();
         Locale locale = new Locale("pl", "PL");
@@ -70,7 +73,6 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testDateWithLocaleFrance() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
 
         Map<String, Object> map = new HashMap<String, Object>();
         Locale locale = new Locale("fr", "FR");
@@ -85,7 +87,6 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testDateWithLocaleUK() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
 
         Map<String, Object> map = new HashMap<String, Object>();
         Locale locale = new Locale("en", "US");
@@ -117,7 +118,6 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testEmptyArrayConversion() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, new Object[]{}, Object[].class);
         // we must not get XWorkException as that will caused a conversion error
         assertEquals(Object[].class, convertedObject.getClass());
@@ -126,7 +126,6 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testNullArrayConversion() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue(new HashMap<String, Object>(), null, null, null, null, Object[].class);
         // we must not get XWorkException as that will caused a conversion error
         assertNull(convertedObject);
@@ -165,10 +164,10 @@ public class XWorkBasicConverterTest ext
     */
 
     public void testDoubleValues() {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
+        NumberConverter numberConverter = new NumberConverter();
 
-        assertTrue(basicConverter.isInRange(-1.2, "-1.2", Double.class));
-        assertTrue(basicConverter.isInRange(1.5, "1.5", Double.class));
+        assertTrue(numberConverter.isInRange(-1.2, "-1.2", Double.class));
+        assertTrue(numberConverter.isInRange(1.5, "1.5", Double.class));
 
         Object value = basicConverter.convertValue("-1.3", double.class);
         assertNotNull(value);
@@ -196,10 +195,10 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testFloatValues() {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
+        NumberConverter numberConverter = new NumberConverter();
 
-        assertTrue(basicConverter.isInRange(-1.65, "-1.65", Float.class));
-        assertTrue(basicConverter.isInRange(1.9876, "1.9876", float.class));
+        assertTrue(numberConverter.isInRange(-1.65, "-1.65", Float.class));
+        assertTrue(numberConverter.isInRange(1.9876, "1.9876", float.class));
 
         Float value = (Float) basicConverter.convertValue("-1.444401", Float.class);
         assertNotNull(value);
@@ -211,14 +210,12 @@ public class XWorkBasicConverterTest ext
     }
 
     public void testNegativeFloatValue() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue("-94.1231233", Float.class);
         assertTrue(convertedObject instanceof Float);
         assertEquals(-94.1231233f, ((Float) convertedObject).floatValue(), 0.0001);
     }
 
     public void testPositiveFloatValue() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue("94.1231233", Float.class);
         assertTrue(convertedObject instanceof Float);
         assertEquals(94.1231233f, ((Float) convertedObject).floatValue(), 0.0001);
@@ -226,21 +223,18 @@ public class XWorkBasicConverterTest ext
 
 
     public void testNegativeDoubleValue() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue("-94.1231233", Double.class);
         assertTrue(convertedObject instanceof Double);
         assertEquals(-94.1231233d, ((Double) convertedObject).doubleValue(), 0.0001);
     }
 
     public void testPositiveDoubleValue() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue("94.1231233", Double.class);
         assertTrue(convertedObject instanceof Double);
         assertEquals(94.1231233d, ((Double) convertedObject).doubleValue(), 0.0001);
     }
 
     public void testNestedEnumValue() throws Exception {
-        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
         Object convertedObject = basicConverter.convertValue(ParentClass.NestedEnum.TEST.name(), ParentClass.NestedEnum.class);
         assertTrue(convertedObject instanceof ParentClass.NestedEnum);
         assertEquals(ParentClass.NestedEnum.TEST, convertedObject);
@@ -248,14 +242,25 @@ public class XWorkBasicConverterTest ext
 
 
     public void testConvert() {
-        XWorkBasicConverter converter = new XWorkBasicConverter();
         Map context = new HashMap();
         Person o = new Person();
         Member member = null;
         String s = "names";
         Object value = new Person[0];
         Class toType = String.class;
-        converter.convertValue(context, value, member, s, value, toType);
-    }     
+        basicConverter.convertValue(context, value, member, s, value, toType);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        basicConverter = container.getInstance(XWorkBasicConverter.class);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        ActionContext.setContext(null);
+    }
+
 
 }

Modified: struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java
URL: http://svn.apache.org/viewvc/struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java?rev=1297347&r1=1297346&r2=1297347&view=diff
==============================================================================
--- struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java (original)
+++ struts/struts2/trunk/xwork-core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java Tue Mar  6 06:26:38 2012
@@ -15,7 +15,11 @@
  */
 package com.opensymphony.xwork2.conversion.impl;
 
-import com.opensymphony.xwork2.*;
+import com.opensymphony.xwork2.ActionContext;
+import com.opensymphony.xwork2.ModelDrivenAction;
+import com.opensymphony.xwork2.SimpleAction;
+import com.opensymphony.xwork2.TestBean;
+import com.opensymphony.xwork2.XWorkTestCase;
 import com.opensymphony.xwork2.ognl.OgnlValueStack;
 import com.opensymphony.xwork2.test.ModelDrivenAction2;
 import com.opensymphony.xwork2.test.User;
@@ -35,7 +39,16 @@ import java.sql.Timestamp;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Date;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
 
 
 /**
@@ -665,6 +678,17 @@ public class XWorkConverterTest extends 
         assertEquals(321, cat.getFoo().getNumber());
     }
 
+    public void testCollectionConversion() throws Exception {
+        // given
+        String[] col1 = new String[]{"1", "2", "ble", "3"};
+
+        // when
+        Object converted = converter.convertValue(context, new ListAction(), null, "ints", col1, List.class);
+
+        // then
+        assertEquals(converted, Arrays.asList(1, 2, 3));
+    }
+
     public static class Foo1 {
         public Bar1 getBar() {
             return new Bar1Impl();
@@ -690,3 +714,17 @@ public class XWorkConverterTest extends 
     }
 
 }
+
+class ListAction {
+
+    private List<Integer> ints = new ArrayList<Integer>();
+
+    public List<Integer> getInts() {
+        return ints;
+    }
+
+    public void setInts(List<Integer> ints) {
+        this.ints = ints;
+    }
+
+}
\ No newline at end of file