WW-3650 Supports double conversion for different locale
Project: http://git-wip-us.apache.org/repos/asf/struts/repo Commit: http://git-wip-us.apache.org/repos/asf/struts/commit/266d78d3 Tree: http://git-wip-us.apache.org/repos/asf/struts/tree/266d78d3 Diff: http://git-wip-us.apache.org/repos/asf/struts/diff/266d78d3 Branch: refs/heads/master Commit: 266d78d32c786276f37ae701267f6719ea9f8a75 Parents: f874f9c Author: Lukasz Lenart <[email protected]> Authored: Fri May 12 13:48:14 2017 +0200 Committer: Lukasz Lenart <[email protected]> Committed: Fri May 12 13:48:14 2017 +0200 ---------------------------------------------------------------------- .../xwork2/conversion/impl/NumberConverter.java | 69 ++++++++++++++++---- .../conversion/impl/NumberConverterTest.java | 27 ++++++++ .../conversion/impl/XWorkConverterTest.java | 24 +++---- 3 files changed, 94 insertions(+), 26 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/struts/blob/266d78d3/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java index 16bbd49..c4a2a1d 100644 --- a/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java +++ b/core/src/main/java/com/opensymphony/xwork2/conversion/impl/NumberConverter.java @@ -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(); + strValue = normalize(strValue, separator); + } - // 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), ""); - } + 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()); } - 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); + 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) { http://git-wip-us.apache.org/repos/asf/struts/blob/266d78d3/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java index ca87aae..8143b00 100644 --- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/NumberConverterTest.java @@ -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); + } + + } http://git-wip-us.apache.org/repos/asf/struts/blob/266d78d3/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java index be96416..4607805 100644 --- a/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java +++ b/core/src/test/java/com/opensymphony/xwork2/conversion/impl/XWorkConverterTest.java @@ -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));
