WW-3650 Supports double conversion for different locale

This commit is contained in:
Lukasz Lenart
2017-05-12 13:48:14 +02:00
parent f874f9cde5
commit 266d78d32c
3 changed files with 95 additions and 27 deletions
@@ -1,6 +1,7 @@
package com.opensymphony.xwork2.conversion.impl;
import com.opensymphony.xwork2.XWorkException;
import com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.message.ParameterizedMessage;
@@ -28,6 +29,8 @@ public class NumberConverter extends DefaultTypeConverter {
return convertToBigDecimal(context, value);
} else if (toType == BigInteger.class) {
return new BigInteger((String) value);
} else if (toType == Double.class || toType == double.class) {
return convertToDouble(context, value);
} else if (toType.isPrimitive()) {
Object convertedValue = super.convertValue(context, value, toType);
String stringValue = (String) value;
@@ -74,27 +77,65 @@ public class NumberConverter extends DefaultTypeConverter {
Locale locale = getLocale(context);
String strValue = String.valueOf(value);
NumberFormat format = NumberFormat.getNumberInstance(locale);
format.setGroupingUsed(true);
NumberFormat format = getNumberFormat(locale);
if (format instanceof DecimalFormat) {
((DecimalFormat) format).setParseBigDecimal(true);
char separator = ((DecimalFormat) format).getDecimalFormatSymbols().getGroupingSeparator();
// this is a hack as \160 isn't the same as " " (an empty space)
if (separator == 160) {
strValue = strValue.replaceAll(" ", "");
} else {
strValue = strValue.replaceAll(String.valueOf(separator), "");
}
strValue = normalize(strValue, separator);
}
try {
LOG.info("Trying parse value {} with locale {}", strValue, locale);
return format.parse(strValue);
} catch (ParseException e) {
LOG.warn(new ParameterizedMessage("Cannot convert value {} to BigDecimal, trying with default converter", value, e));
return super.convertValue(context, value, BigDecimal.class);
LOG.debug("Trying to convert a value {} with locale {} to BigDecimal", strValue, locale);
ParsePosition parsePosition = new ParsePosition(0);
Number number = format.parse(strValue, parsePosition);
if (parsePosition.getIndex() != strValue.length()) {
throw new XWorkException("Unparseable number: \"" + strValue + "\" at position " + parsePosition.getIndex());
}
return number;
}
protected Object convertToDouble(Map<String, Object> context, Object value) {
Locale locale = getLocale(context);
String strValue = String.valueOf(value);
NumberFormat format = getNumberFormat(locale);
if (format instanceof DecimalFormat) {
char separator = ((DecimalFormat) format).getDecimalFormatSymbols().getGroupingSeparator();
strValue = normalize(strValue, separator);
}
LOG.debug("Trying to convert a value {} with locale {} to Double", strValue, locale);
ParsePosition parsePosition = new ParsePosition(0);
Number number = format.parse(strValue, parsePosition);
if (parsePosition.getIndex() != strValue.length()) {
throw new XWorkException("Unparseable number: \"" + strValue + "\" at position " + parsePosition.getIndex());
}
if (!isInRange(number, strValue, Double.class)) {
throw new XWorkException("Overflow or underflow converting: \"" + strValue + "\" into class " + number.getClass().getName());
}
if (number != null) {
return number.doubleValue();
}
return null;
}
protected NumberFormat getNumberFormat(Locale locale) {
NumberFormat format = NumberFormat.getNumberInstance(locale);
format.setGroupingUsed(true);
return format;
}
protected String normalize(String strValue, char separator) {
// this is a hack as \160 isn't the same as " " (an empty space)
if (separator == 160) {
strValue = strValue.replaceAll(" ", String.valueOf(separator));
}
return strValue;
}
protected boolean isInRange(Number value, String stringValue, Class toType) {
@@ -81,4 +81,31 @@ public class NumberConverterTest extends XWorkTestCase {
assertEquals(BigDecimal.valueOf(100234.4), value);
}
public void testStringToDoubleConversionPL() throws Exception {
// given
NumberConverter converter = new NumberConverter();
Map<String, Object> context = new HashMap<>();
context.put(ActionContext.LOCALE, new Locale("pl", "PL"));
// when
Object value = converter.convertValue(context, null, null, null, "1234,4567", Double.class);
// then
assertEquals(1234.4567, value);
}
public void testStringToDoubleConversionWithDotsPL() throws Exception {
// given
NumberConverter converter = new NumberConverter();
Map<String, Object> context = new HashMap<>();
context.put(ActionContext.LOCALE, new Locale("pl", "PL"));
// when
Object value = converter.convertValue(context, null, null, null, "1 234,4", Double.class);
// then
assertEquals(1234.4, value);
}
}
@@ -519,30 +519,30 @@ public class XWorkConverterTest extends XWorkTestCase {
}
public void testStringToPrimitiveDouble() {
assertEquals(new Double(123), converter.convertValue(context, null, null, null, "123", double.class));
assertEquals(123d, converter.convertValue(context, null, null, null, "123", double.class));
context.put(ActionContext.LOCALE, Locale.US);
assertEquals(new Double(123.12), converter.convertValue(context, null, null, null, "123.12", double.class));
assertEquals(123.12, converter.convertValue(context, null, null, null, "123.12", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "123aa", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "aa123", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1,234", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1,234.12", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1,23", double.class));
assertEquals(new Double(1.234), converter.convertValue(context, null, null, null, "1.234", double.class));
assertEquals(1234d, converter.convertValue(context, null, null, null, "1,234", double.class));
assertEquals(1234.12, converter.convertValue(context, null, null, null, "1,234.12", double.class));
assertEquals(123d, converter.convertValue(context, null, null, null, "1,23", double.class));
assertEquals(1.234, converter.convertValue(context, null, null, null, "1.234", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1.234,12", double.class));
context.put(ActionContext.LOCALE, Locale.GERMANY);
assertEquals(new Double(123.12), converter.convertValue(context, null, null, null, "123.12", double.class));
assertEquals(12312d, converter.convertValue(context, null, null, null, "123.12", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "123aa", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "aa123", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1,234", double.class));
assertEquals(1.234, converter.convertValue(context, null, null, null, "1,234", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1,234.12", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1,23", double.class));
assertEquals(new Double(1.234), converter.convertValue(context, null, null, null, "1.234", double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "1.234,12", double.class));
assertEquals(1.23, converter.convertValue(context, null, null, null, "1,23", double.class));
assertEquals(1234d, converter.convertValue(context, null, null, null, "1.234", double.class));
assertEquals(1234.12, converter.convertValue(context, null, null, null, "1.234,12", double.class));
}
public void testStringToDouble() {
assertEquals(new Double(123), converter.convertValue(context, null, null, null, "123", Double.class));
assertEquals(123d, converter.convertValue(context, null, null, null, "123", Double.class));
context.put(ActionContext.LOCALE, Locale.US);
assertEquals(new Double(123.12), converter.convertValue(context, null, null, null, "123.12", Double.class));
assertEquals(OgnlRuntime.NoConversionPossible, converter.convertValue(context, null, null, null, "123aa", Double.class));