Commits

Anonymous committed 14dcff5

XWorkBasicConverter.doConvertToString(...) ignores Locale for instances of Number
o applied patch provided by Claus Ibsen, thanks!

Issue Number: XW-490

git-svn-id: http://svn.opensymphony.com/svn/xwork/branches/2.0@1482e221344d-f017-0410-9bd5-d282ab1896d7

Comments (0)

Files changed (3)

src/java/com/opensymphony/xwork2/util/XWorkBasicConverter.java

 public class XWorkBasicConverter extends DefaultTypeConverter {
 
     private static final String MILLISECOND_FORMAT = ".SSS";
-    private static final String RFC3339_FORMAT = "yyyy-MM-dd'T'HH:mm:ss";
 
     public Object convertValue(Map context, Object o, Member member, String s, Object value, Class toType) {
         Object result = null;
         }
 
         if (toType == String.class) {
+            Class inputType = value.getClass();
+            // if input (value) is a number then use special conversion method (XW-490)
+            if (Number.class.isAssignableFrom(inputType)) {
+                result = doConvertFromNumberToString(context, value, inputType);
+                if (result != null) {
+                    return result;
+                }
+            }
+            // okay use default string conversion
             result = doConvertToString(context, value);
         } else if (toType == boolean.class) {
             result = doConvertToBoolean(value);
     private Class doConvertToClass(Object value) {
         Class clazz = null;
 
-        if (value instanceof String && value != null && ((String)value).length() > 0) {
+        if (value instanceof String && value != null && ((String) value).length() > 0) {
             try {
                 clazz = Class.forName((String) value);
             } catch (ClassNotFoundException e) {
     private Object doConvertToDate(Map context, Object value, Class toType) {
         Date result = null;
 
-        if (value instanceof String && value != null && ((String)value).length() > 0) {
+        if (value instanceof String && value != null && ((String) value).length() > 0) {
             String sa = (String) value;
             Locale locale = getLocale(context);
 
                     } catch (ParseException ignore) {
                     }
                 }
-             } else if(java.util.Date.class == toType) {
-            	Date check = null;
-                SimpleDateFormat d1 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
-                SimpleDateFormat d2 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
-                SimpleDateFormat d3 = (SimpleDateFormat)DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
-                SimpleDateFormat rfc3339Format = new SimpleDateFormat(RFC3339_FORMAT);
-                SimpleDateFormat[] dfs = {d1, d2, d3, rfc3339Format}; //added RFC 3339 date format (XW-473)
+            } else if (java.util.Date.class == toType) {
+                Date check = null;
+                SimpleDateFormat d1 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.LONG, locale);
+                SimpleDateFormat d2 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.MEDIUM, locale);
+                SimpleDateFormat d3 = (SimpleDateFormat) DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
+                SimpleDateFormat rfc3399 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+                SimpleDateFormat[] dfs = {d1, d2, d3, rfc3399}; //added RFC 3339 date format (XW-473)
                 for (int i = 0; i < dfs.length; i++) {
-                	try {
-                		check = dfs[i].parse(sa);
-                		df = dfs[i];
-                		if (check != null) {
-                			break;
-                		}
-                	}
-                	catch (ParseException ignore) {
-                	}
+                    try {
+                        check = dfs[i].parse(sa);
+                        df = dfs[i];
+                        if (check != null) {
+                            break;
+                        }
+                    }
+                    catch (ParseException ignore) {
+                    }
                 }
             }
             //final fallback for dates without time
-            if (df == null){
-            	df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
+            if (df == null) {
+                df = DateFormat.getDateInstance(DateFormat.SHORT, locale);
             }
             try {
-            	df.setLenient(false); // let's use strict parsing (XW-341)
+                df.setLenient(false); // let's use strict parsing (XW-341)
                 result = df.parse(sa);
-                if (! (Date.class == toType)) {
+                if (!(Date.class == toType)) {
                     try {
                         Constructor constructor = toType.getConstructor(new Class[]{long.class});
                         return constructor.newInstance(new Object[]{new Long(result.getTime())});
                 return new BigInteger((String) value);
             } else {
                 String stringValue = (String) value;
-                if ( !toType.isPrimitive() && (stringValue == null || stringValue.length() == 0)) {
+                if (!toType.isPrimitive() && (stringValue == null || stringValue.length() == 0)) {
                     return null;
                 }
                 NumberFormat numFormat = NumberFormat.getInstance(getLocale(context));
                 if (parsePos.getIndex() != stringValue.length()) {
                     throw new XWorkException("Unparseable number: \"" + stringValue + "\" at position "
                             + parsePos.getIndex());
-                }
-                else {
+                } else {
                     value = super.convertValue(context, number, toType);
                 }
             }
         return true;
     }
 
+    /**
+     * Converts the input as a number using java's number formatter to a string output.
+     */
+    private String doConvertFromNumberToString(Map 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 context, Object value) {
         String result = null;
 

src/test/com/opensymphony/xwork2/util/XWorkBasicConverterTest.java

 
 import java.util.Date;
 import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
 
 import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.ActionContext;
 
 import junit.framework.TestCase;
 
 /**
  * Test case for XWorkBasicConverter
- * 
+ *
  * @author tm_jee
  * @version $Date$ $Id$
  */
 public class XWorkBasicConverterTest extends TestCase {
 
-	public void test() {
-		// TODO: test for every possible conversion
-		// take into account of empty string
-		// primitive -> conversion error when empty string is passed
-		// object -> return null when empty string is passed
-	}
-	
-	
-	// TODO: more test will come soon !!!
-	
-	// TEST DATE CONVERSION:-
-	public void testDateConversionWithEmptyValue() {
-		XWorkBasicConverter basicConverter = new XWorkBasicConverter();
-		Object convertedObject = basicConverter.convertValue(new HashMap(), null, null, null, "", Date.class);
-		// we must not get XWorkException as that will caused a conversion error
-		assertNull(convertedObject); 
-	}
-	
-	public void testDateConversionWithInvalidValue() {
-		XWorkBasicConverter basicConverter = new XWorkBasicConverter();
-		try {
-			Object convertedObject = basicConverter.convertValue(new HashMap(), null, null, null, "asdsd", Date.class);
-		}
-		catch(XWorkException e) {
-			// we MUST get this exception as this is a conversion error
-			assertTrue(true);
-			return;
-		}
-		fail("XWorkException expected - conversion error occurred");
-	}
+    public void test() {
+        // TODO: test for every possible conversion
+        // take into account of empty string
+        // primitive -> conversion error when empty string is passed
+        // object -> return null when empty string is passed
+    }
+
+    // TODO: more test will come soon !!!
+
+    public void testDateConversionWithEmptyValue() {
+        XWorkBasicConverter basicConverter = new XWorkBasicConverter();
+        Object convertedObject = basicConverter.convertValue(new HashMap(), 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(), null, null, null, "asdsd", Date.class);
+            fail("XWorkException expected - conversion error occurred");
+        } catch (XWorkException e) {
+            // we MUST get this exception as this is a conversion error
+        }
+    }
+
+    public void testXW490ConvertStringToDobule() throws Exception {
+        Locale locale = new Locale("DA"); // let's use a not common locale such as Denmark
+
+        Map ctx = new HashMap();
+        ctx.put(ActionContext.LOCALE, locale);
+
+        XWorkBasicConverter conv = new XWorkBasicConverter();
+        // decimal seperator is , in Denmark so we should write 123,99 as input
+        Double value = (Double) conv.convertValue(ctx, null, null, null, "123,99", Double.class);
+        assertNotNull(value);
+
+        // output is as expected a real double value converted using Denmark as locale
+        assertEquals(123.99d, value.doubleValue(), 0.001d);
+    }
+
+    public void testXW49ConvertDobuleToString() throws Exception {
+        Locale locale = new Locale("DA"); // let's use a not common locale such as Denmark
+
+        Map ctx = new HashMap();
+        ctx.put(ActionContext.LOCALE, locale);
+
+        XWorkBasicConverter conv = new XWorkBasicConverter();
+        // decimal seperator is , in Denmark so we should write 123,99 as input
+        String value = (String) conv.convertValue(ctx, null, null, null, new Double("123.99"), String.class);
+        assertNotNull(value);
+
+        // output should be formatted according to Danish locale using , as decimal seperator
+        assertEquals("123,99", value);
+    }
 }

src/test/com/opensymphony/xwork2/validator/DoubleRangeValidatorTest.java

 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Locale;
 
 /**
  * Unit test for {@link DoubleRangeFieldValidator}.
 public class DoubleRangeValidatorTest extends XWorkTestCase {
 
     public void testRangeValidationWithError() throws Exception {
+        // must set a locale to US as error message contains a locale dependent number (see XW-490)
+        Locale defLocale = Locale.getDefault();
+        Locale.setDefault(Locale.US);
+
         ActionProxy proxy = actionProxyFactory.createActionProxy("", MockConfigurationProvider.VALIDATION_ACTION_NAME, null);
         proxy.execute();
         assertTrue(((ValidationAware) proxy.getAction()).hasFieldErrors());
         String errorMessage = (String) errorMessages.get(0);
         assertNotNull("Expecting: percentage must be between 0.1 and 10.1, current value is 100.0123.", errorMessage);
         assertEquals("percentage must be between 0.1 and 10.1, current value is 100.0123.", errorMessage);
+
+        Locale.setDefault(defLocale);
     }
 
     public void testRangeValidationNoError() throws Exception {
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.