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