diff --git a/src/main/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java b/src/main/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java index 6040c2d0a..c9dbb4082 100644 --- a/src/main/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java +++ b/src/main/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverter.java @@ -182,4 +182,9 @@ protected Object parse(final Object value, final String pattern) throws ParseExc throw new ConversionException("Suplied number is not of type BigDecimal: " + result); } } + + @Override + protected boolean isParseBigDecimal() { + return true; + } } diff --git a/src/main/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java b/src/main/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java index 70bb6239d..13bf58b43 100644 --- a/src/main/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java +++ b/src/main/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverter.java @@ -17,6 +17,7 @@ package org.apache.commons.beanutils.locale.converters; +import java.math.BigDecimal; import java.math.BigInteger; import java.text.ParseException; import java.util.Locale; @@ -176,6 +177,9 @@ protected Object parse(final Object value, final String pattern) throws ParseExc if (result == null || result instanceof BigInteger) { return result; } + if (result instanceof BigDecimal) { + return ((BigDecimal) result).toBigInteger(); + } if (result instanceof Number) { return BigInteger.valueOf(((Number) result).longValue()); } @@ -185,4 +189,9 @@ protected Object parse(final Object value, final String pattern) throws ParseExc throw new ConversionException("Suplied number is not of type BigInteger: " + result); } } + + @Override + protected boolean isParseBigDecimal() { + return true; + } } diff --git a/src/main/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java b/src/main/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java index e35123493..acf9af723 100644 --- a/src/main/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java +++ b/src/main/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverter.java @@ -178,6 +178,18 @@ public DecimalLocaleConverter(final Object defaultValue, final Locale locale, fi * @throws org.apache.commons.beanutils.ConversionException if conversion cannot be performed successfully. * @throws ParseException if an error occurs parsing a String to a Number. */ + /** + * Tests whether the underlying {@link DecimalFormat} should parse into a {@link java.math.BigDecimal} so that magnitude and precision are preserved. + * Subclasses that build {@link java.math.BigInteger} or {@link java.math.BigDecimal} values override this to return {@code true}; the narrowing converters + * keep the default {@code Long} / {@code Double} result. + * + * @return {@code true} to parse into a {@link java.math.BigDecimal}, {@code false} otherwise. + * @since 1.11.1 + */ + protected boolean isParseBigDecimal() { + return false; + } + @Override protected Object parse(final Object value, final String pattern) throws ParseException { if (value instanceof Number) { @@ -188,6 +200,7 @@ protected Object parse(final Object value, final String pattern) throws ParseExc // representation, each call to getInstance actually returns a new // object. final DecimalFormat formatter = (DecimalFormat) NumberFormat.getInstance(locale); + formatter.setParseBigDecimal(isParseBigDecimal()); // if some constructors default pattern to null, it makes only sense // to handle null pattern gracefully if (pattern != null) { diff --git a/src/test/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverterTest.java b/src/test/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverterTest.java index 4cac72eda..646d4973f 100644 --- a/src/test/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverterTest.java +++ b/src/test/java/org/apache/commons/beanutils/locale/converters/BigDecimalLocaleConverterTest.java @@ -228,5 +228,13 @@ public void testConstructorMain() { } + /** + * Test that a value beyond {@code double} precision is preserved instead of being rounded to a lossy {@code 1.0E+19}. + */ + public void testConvertLargeValueKeepsPrecision() { + converter = new BigDecimalLocaleConverter(); + convertValueNoPattern(converter, "9999999999999999999", new BigDecimal("9999999999999999999")); + } + } diff --git a/src/test/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverterTest.java b/src/test/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverterTest.java index acf3ece1e..909ffcb54 100644 --- a/src/test/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverterTest.java +++ b/src/test/java/org/apache/commons/beanutils/locale/converters/BigIntegerLocaleConverterTest.java @@ -229,6 +229,15 @@ public void testConstructorMain() { } + /** + * Test that a value beyond {@code long} range keeps its full magnitude instead of being clamped to {@code Long.MAX_VALUE}. + */ + public void testConvertLargeValueKeepsMagnitude() { + converter = new BigIntegerLocaleConverter(); + convertValueNoPattern(converter, "9999999999999999999", new BigInteger("9999999999999999999")); + convertValueNoPattern(converter, "123456789012345678901234567890", new BigInteger("123456789012345678901234567890")); + } + /** * Tries to convert to an unsupported type. This tests behavior of the base * class. All locale converters should react in the same way.