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 8b1586ac Reject trailing characters in DecimalLocaleConverter.parse 
(#400)
8b1586ac is described below

commit 8b1586ac980c81745484d60417fd9ebd60c751fd
Author: Dexter.k <[email protected]>
AuthorDate: Sun Jun 21 19:41:16 2026 +0000

    Reject trailing characters in DecimalLocaleConverter.parse (#400)
    
    DecimalFormat.parse(String) stops at the first unparsable character and
    drops the rest, so the locale numeric converters accepted trailing
    garbage (123abc -> 123, '42 OR 1=1' -> 42). Every numeric locale
    converter routes through DecimalLocaleConverter.parse, while the sibling
    DateLocaleConverter already rejects leftover input via a ParsePosition
    check. Switch to the same form and throw ParseException unless the whole
    string is consumed.
    
    Port of the 2.x fix to the 1.X branch. Updates the now-stale (B)
    assertions across the numeric locale converter tests, which pinned the
    old partial-parse values and now fall through to the converter default.
---
 .../locale/converters/DecimalLocaleConverter.java  |  9 ++-
 .../converters/BigDecimalLocaleConverterTest.java  |  8 +--
 .../converters/BigIntegerLocaleConverterTest.java  |  8 +--
 .../converters/DecimalLocaleConverterTest.java     | 66 ++++++++++++++++++++++
 .../converters/DoubleLocaleConverterTest.java      |  8 +--
 .../converters/FloatLocaleConverterTest.java       |  8 +--
 .../converters/IntegerLocaleConverterTest.java     |  8 +--
 .../locale/converters/LongLocaleConverterTest.java |  8 +--
 .../converters/ShortLocaleConverterTest.java       |  8 +--
 9 files changed, 95 insertions(+), 36 deletions(-)

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 ada0e00d..69417a23 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
@@ -20,6 +20,7 @@ package org.apache.commons.beanutils.locale.converters;
 import java.text.DecimalFormat;
 import java.text.NumberFormat;
 import java.text.ParseException;
+import java.text.ParsePosition;
 import java.util.Locale;
 
 import org.apache.commons.beanutils.locale.BaseLocaleConverter;
@@ -239,6 +240,12 @@ public class DecimalLocaleConverter extends 
BaseLocaleConverter {
             log.debug("No pattern provided, using default.");
         }
 
-        return formatter.parse((String) value);
+        final String strValue = (String) value;
+        final ParsePosition pos = new ParsePosition(0);
+        final Number parsed = formatter.parse(strValue, pos);
+        if (parsed == null || pos.getErrorIndex() >= 0 || pos.getIndex() != 
strValue.length()) {
+            throw new ParseException("Error parsing '" + strValue + "' as a 
number", pos.getIndex());
+        }
+        return parsed;
     }
 }
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 527a58de..4cac72ed 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
@@ -193,12 +193,10 @@ public class BigDecimalLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertNull(converter, "(A)", defaultValue);
 
         // 
**************************************************************************
-        // Convert value in the wrong format - maybe you would expect it to 
throw an
-        // exception and return the default - it doesn't, DecimalFormat parses 
it
-        // quite happily turning "1,234.56" into "1.234"
-        // I guess this is one of the limitations of DecimalFormat
+        // Convert value in the wrong format - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueNoPattern(converter, "(B)", defaultDecimalValue, new 
BigDecimal("1.234"));
+        convertValueNoPattern(converter, "(B)", defaultDecimalValue, 
defaultValue);
 
         // 
**************************************************************************
         // Convert with non-localized pattern - this causes an exception in 
parse()
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 4413d24d..acf3ece1 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
@@ -203,12 +203,10 @@ public class BigIntegerLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertValueNoPattern(converter, "(B)", defaultIntegerValue, new 
BigInteger("1"));
 
         // 
**************************************************************************
-        // Convert with non-localized pattern - unlike the equivalent 
BigDecimal Test Case
-        // it doesn't causes an exception in parse() - DecimalFormat parses it
-        // quite happily turning "1,234" into "1"
-        // Again this is one of the limitations of DecimalFormat
+        // Convert with non-localized pattern - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, new BigInteger("1"));
+        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, defaultValue);
 
         // 
**************************************************************************
         // Convert with specified type
diff --git 
a/src/test/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverterTest.java
 
b/src/test/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverterTest.java
new file mode 100644
index 00000000..ddcecd51
--- /dev/null
+++ 
b/src/test/java/org/apache/commons/beanutils/locale/converters/DecimalLocaleConverterTest.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.beanutils.locale.converters;
+
+import java.util.Locale;
+
+import org.apache.commons.beanutils.ConversionException;
+
+/**
+ * Tests that {@link DecimalLocaleConverter} fully consumes its input and 
rejects trailing, unparsed characters.
+ */
+public class DecimalLocaleConverterTest extends BaseLocaleConverterTest {
+
+    public DecimalLocaleConverterTest(final String name) {
+        super(name);
+    }
+
+    /**
+     * A grouped number is still parsed in full.
+     */
+    public void testParseAcceptsGroupedNumber() {
+        final IntegerLocaleConverter converter = new 
IntegerLocaleConverter(Locale.US);
+        assertEquals(Integer.valueOf(1234), converter.convert("1,234"));
+    }
+
+    /**
+     * Trailing characters left after a partial parse are rejected.
+     */
+    public void testParseRejectsTrailingCharacters() {
+        final IntegerLocaleConverter converter = new 
IntegerLocaleConverter(Locale.US);
+        try {
+            converter.convert("123abc");
+            fail("Expected ConversionException for trailing characters");
+        } catch (final ConversionException expected) {
+            // expected
+        }
+    }
+
+    /**
+     * A numeric prefix followed by an expression is rejected.
+     */
+    public void testParseRejectsTrailingExpression() {
+        final IntegerLocaleConverter converter = new 
IntegerLocaleConverter(Locale.US);
+        try {
+            converter.convert("42 OR 1=1");
+            fail("Expected ConversionException for trailing expression");
+        } catch (final ConversionException expected) {
+            // expected
+        }
+    }
+}
diff --git 
a/src/test/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverterTest.java
 
b/src/test/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverterTest.java
index ccbef9da..c52ba980 100644
--- 
a/src/test/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverterTest.java
+++ 
b/src/test/java/org/apache/commons/beanutils/locale/converters/DoubleLocaleConverterTest.java
@@ -191,12 +191,10 @@ public class DoubleLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertNull(converter, "(A)", defaultValue);
 
         // 
**************************************************************************
-        // Convert value in the wrong format - maybe you would expect it to 
throw an
-        // exception and return the default - it doesn't, DecimalFormat parses 
it
-        // quite happily turning "1,234.56" into "1.234"
-        // I guess this is one of the limitations of DecimalFormat
+        // Convert value in the wrong format - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueNoPattern(converter, "(B)", defaultDecimalValue, 
Double.valueOf("1.234"));
+        convertValueNoPattern(converter, "(B)", defaultDecimalValue, 
defaultValue);
 
         // 
**************************************************************************
         // Convert with non-localized pattern - this causes an exception in 
parse()
diff --git 
a/src/test/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverterTest.java
 
b/src/test/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverterTest.java
index a98752b8..55b8f659 100644
--- 
a/src/test/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverterTest.java
+++ 
b/src/test/java/org/apache/commons/beanutils/locale/converters/FloatLocaleConverterTest.java
@@ -197,12 +197,10 @@ public class FloatLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertNull(converter, "(A)", defaultValue);
 
         // 
**************************************************************************
-        // Convert value in the wrong format - maybe you would expect it to 
throw an
-        // exception and return the default - it doesn't, DecimalFormat parses 
it
-        // quite happily turning "1,234.56" into "1.234"
-        // I guess this is one of the limitations of DecimalFormat
+        // Convert value in the wrong format - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueNoPattern(converter, "(B)", defaultDecimalValue, 
Float.valueOf("1.234"));
+        convertValueNoPattern(converter, "(B)", defaultDecimalValue, 
defaultValue);
 
         // 
**************************************************************************
         // Convert with non-localized pattern - this causes an exception in 
parse()
diff --git 
a/src/test/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverterTest.java
 
b/src/test/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverterTest.java
index fb9b02b3..24ff04a8 100644
--- 
a/src/test/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverterTest.java
+++ 
b/src/test/java/org/apache/commons/beanutils/locale/converters/IntegerLocaleConverterTest.java
@@ -191,12 +191,10 @@ public class IntegerLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertValueNoPattern(converter, "(B)", defaultIntegerValue, 
Integer.valueOf("1"));
 
         // 
**************************************************************************
-        // Convert with non-localized pattern - unlike the equivalent 
BigDecimal Test Case
-        // it doesn't causes an exception in parse() - DecimalFormat parses it
-        // quite happily turning "1,234" into "1"
-        // Again this is one of the limitations of DecimalFormat
+        // Convert with non-localized pattern - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, Integer.valueOf("1"));
+        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, defaultValue);
 
         // 
**************************************************************************
         // Convert with specified type
diff --git 
a/src/test/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverterTest.java
 
b/src/test/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverterTest.java
index fd7298e3..0d4b3c0d 100644
--- 
a/src/test/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverterTest.java
+++ 
b/src/test/java/org/apache/commons/beanutils/locale/converters/LongLocaleConverterTest.java
@@ -199,12 +199,10 @@ public class LongLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertValueNoPattern(converter, "(B)", defaultIntegerValue, 
Long.valueOf("1"));
 
         // 
**************************************************************************
-        // Convert with non-localized pattern - unlike the equivalent 
BigDecimal Test Case
-        // it doesn't causes an exception in parse() - DecimalFormat parses it
-        // quite happily turning "1,234" into "1"
-        // Again this is one of the limitations of DecimalFormat
+        // Convert with non-localized pattern - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, Long.valueOf("1"));
+        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, defaultValue);
 
         // 
**************************************************************************
         // Convert with specified type
diff --git 
a/src/test/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverterTest.java
 
b/src/test/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverterTest.java
index 71974957..7073aa69 100644
--- 
a/src/test/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverterTest.java
+++ 
b/src/test/java/org/apache/commons/beanutils/locale/converters/ShortLocaleConverterTest.java
@@ -199,12 +199,10 @@ public class ShortLocaleConverterTest extends 
BaseLocaleConverterTest {
         convertValueNoPattern(converter, "(B)", defaultIntegerValue, 
Short.valueOf("1"));
 
         // 
**************************************************************************
-        // Convert with non-localized pattern - unlike the equivalent 
BigDecimal Test Case
-        // it doesn't causes an exception in parse() - DecimalFormat parses it
-        // quite happily turning "1,234" into "1"
-        // Again this is one of the limitations of DecimalFormat
+        // Convert with non-localized pattern - the trailing characters left 
after the
+        // partial parse are now rejected, so the converter returns the 
default.
         // 
**************************************************************************
-        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, Short.valueOf("1"));
+        convertValueWithPattern(converter, "(B)", localizedIntegerValue, 
defaultIntegerPattern, defaultValue);
 
         // 
**************************************************************************
         // Convert with specified type

Reply via email to