This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch 1.X
in repository https://gitbox.apache.org/repos/asf/commons-beanutils.git


The following commit(s) were added to refs/heads/1.X by this push:
     new 65b6f8ab Preserve magnitude in BigInteger and BigDecimal locale 
converters (#403)
65b6f8ab is described below

commit 65b6f8abcf048944a51bf4149feb7d183c73a548
Author: Dexter.k <[email protected]>
AuthorDate: Mon Jun 22 13:39:39 2026 +0000

    Preserve magnitude in BigInteger and BigDecimal locale converters (#403)
    
    DecimalLocaleConverter.parse builds a DecimalFormat without enabling
    setParseBigDecimal, so a value past long/double range comes back from
    DecimalFormat.parse as a clamped Long or a lossy Double; the BigInteger
    and BigDecimal converters then derive their result from that Number and
    return it silently wrong (9999999999999999999 -> 9223372036854775807 for
    BigInteger, -> 1.0E+19 for BigDecimal).
    
    Add a protected isParseBigDecimal() hook (default false) and pass it to
    formatter.setParseBigDecimal; only BigIntegerLocaleConverter and
    BigDecimalLocaleConverter override it to true, so DecimalFormat returns a
    lossless BigDecimal for them while the narrowing Byte/Short/Integer/Long/
    Float/Double converters stay on the Long/Double path. 
BigIntegerLocaleConverter
    converts the BigDecimal via toBigInteger().
    
    Found by comparing the locale converters with the non-locale
    BigInteger/BigDecimal converters that parse the string directly.
---
 .../locale/converters/BigDecimalLocaleConverter.java        |  5 +++++
 .../locale/converters/BigIntegerLocaleConverter.java        |  9 +++++++++
 .../beanutils/locale/converters/DecimalLocaleConverter.java | 13 +++++++++++++
 .../locale/converters/BigDecimalLocaleConverterTest.java    |  8 ++++++++
 .../locale/converters/BigIntegerLocaleConverterTest.java    |  9 +++++++++
 5 files changed, 44 insertions(+)

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 6040c2d0..c9dbb408 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 @@ public class BigDecimalLocaleConverter extends 
DecimalLocaleConverter {
             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 70bb6239..13bf58b4 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 @@ public class BigIntegerLocaleConverter extends 
DecimalLocaleConverter {
         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 @@ public class BigIntegerLocaleConverter extends 
DecimalLocaleConverter {
             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 e3512349..acf9af72 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 class DecimalLocaleConverter extends 
BaseLocaleConverter {
      * @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 @@ public class DecimalLocaleConverter extends 
BaseLocaleConverter {
         // 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 4cac72ed..646d4973 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 class BigDecimalLocaleConverterTest extends 
BaseLocaleConverterTest {
 
     }
 
+    /**
+     * 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 acf3ece1..909ffcb5 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 class BigIntegerLocaleConverterTest extends 
BaseLocaleConverterTest {
 
     }
 
+    /**
+     * 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.

Reply via email to