diff --git a/src/main/java/org/apache/commons/beanutils2/locale/converters/DecimalLocaleConverter.java b/src/main/java/org/apache/commons/beanutils2/locale/converters/DecimalLocaleConverter.java index ab60b7d12..bf65ff511 100644 --- a/src/main/java/org/apache/commons/beanutils2/locale/converters/DecimalLocaleConverter.java +++ b/src/main/java/org/apache/commons/beanutils2/locale/converters/DecimalLocaleConverter.java @@ -20,6 +20,7 @@ import java.text.DecimalFormat; import java.text.NumberFormat; import java.text.ParseException; +import java.text.ParsePosition; import java.util.Locale; import org.apache.commons.beanutils2.ConversionException; @@ -129,6 +130,12 @@ protected T parse(final Object value, final String pattern) throws ParseExceptio LOG.debug("No pattern provided, using default."); } - return (T) 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 (T) parsed; } } diff --git a/src/test/java/org/apache/commons/beanutils2/converters/DecimalLocaleConverterTest.java b/src/test/java/org/apache/commons/beanutils2/converters/DecimalLocaleConverterTest.java new file mode 100644 index 000000000..ecfd87941 --- /dev/null +++ b/src/test/java/org/apache/commons/beanutils2/converters/DecimalLocaleConverterTest.java @@ -0,0 +1,67 @@ +/* + * 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.beanutils2.converters; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import java.util.Locale; + +import org.apache.commons.beanutils2.ConversionException; +import org.apache.commons.beanutils2.locale.converters.DecimalLocaleConverter; +import org.apache.commons.beanutils2.locale.converters.IntegerLocaleConverter; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Tests that {@link DecimalLocaleConverter} fully consumes its input and rejects trailing, unparsed characters. + */ +class DecimalLocaleConverterTest { + + private Locale origLocale; + + @BeforeEach + public void setUp() { + origLocale = Locale.getDefault(); + Locale.setDefault(Locale.US); + } + + @AfterEach + public void tearDown() { + Locale.setDefault(origLocale); + } + + @Test + void testParseAcceptsGroupedNumber() { + final IntegerLocaleConverter converter = IntegerLocaleConverter.builder().setLocale(Locale.US).get(); + assertEquals(Integer.valueOf(1234), converter.convert("1,234")); + } + + @Test + void testParseRejectsTrailingCharacters() { + final IntegerLocaleConverter converter = IntegerLocaleConverter.builder().setLocale(Locale.US).get(); + assertThrows(ConversionException.class, () -> converter.convert("123abc")); + } + + @Test + void testParseRejectsTrailingExpression() { + final IntegerLocaleConverter converter = IntegerLocaleConverter.builder().setLocale(Locale.US).get(); + assertThrows(ConversionException.class, () -> converter.convert("42 OR 1=1")); + } +}