This is an automated email from the ASF dual-hosted git repository.
garydgregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-lang.git
The following commit(s) were added to refs/heads/master by this push:
new 48532a6ed Clarify LocaleUtils ASCII validation following #1838
48532a6ed is described below
commit 48532a6ed0e5995673a3181a8eb558058d027242
Author: Gary Gregory <[email protected]>
AuthorDate: Sun Oct 25 09:45:36 2026 -0400
Clarify LocaleUtils ASCII validation following #1838
Document ASCII language, country, and numeric area code requirements and
note that previously accepted non-ASCII codes now throw
IllegalArgumentException. Expand regression coverage for non-ASCII
parsing and cache exclusion.
---
src/changes/changes.xml | 1 +
src/main/java/org/apache/commons/lang3/LocaleUtils.java | 5 +++--
src/test/java/org/apache/commons/lang3/LocaleUtilsTest.java | 10 +++++-----
3 files changed, 9 insertions(+), 7 deletions(-)
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index f56b09564..82d056f1c 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -75,6 +75,7 @@ The <action> type attribute can be add,update,fix,remove.
<action type="fix" dev="ggregory" due-to="Aminark, Gary
Gregory">[javadoc] Correct StringUtils example methods and overloads
(#1836).</action>
<action type="fix" dev="ggregory" due-to="alhuda, Gary
Gregory">Stop ExceptionUtils.removeCommonFrames at the first differing frame
(#1831).</action>
<action type="fix" dev="ggregory" due-to="Gary
Gregory">Use StackTraceElement objects to build compact root cause stack
traces, avoiding text parsing and preventing exception message text from being
mistaken for stack frames.</action>
+ <action type="fix" dev="ggregory" due-to="alhuda, Gary
Gregory">Restrict LocaleUtils.toLocale to ASCII language, country, and numeric
area codes; previously accepted non-ASCII codes now cause
IllegalArgumentException (#1838).</action>
<!-- ADD -->
<!-- UPDATE -->
<action type="update" dev="ggregory" due-to="Gary Gregory">Bump
org.apache.commons:commons-parent from 105 to 106.</action>
diff --git a/src/main/java/org/apache/commons/lang3/LocaleUtils.java
b/src/main/java/org/apache/commons/lang3/LocaleUtils.java
index cbc721c09..2845e8732 100644
--- a/src/main/java/org/apache/commons/lang3/LocaleUtils.java
+++ b/src/main/java/org/apache/commons/lang3/LocaleUtils.java
@@ -416,8 +416,9 @@ public static Locale toLocale(final Locale locale) {
* </p>
*
* <p>
- * This method validates the input strictly. The language code must be
lowercase. The country code must be uppercase. The separator must be an
underscore or
- * a dash. The length must be correct.
+ * This method validates the input strictly. A nonempty language code must
consist of two or three lowercase ASCII letters. A nonempty country code must
+ * consist of two uppercase ASCII letters or, when a language code is
present, three ASCII digits representing a numeric area code. The separator
must be
+ * an underscore or a dash. The length must be correct.
* </p>
*
* @param str The locale String to convert, null returns null.
diff --git a/src/test/java/org/apache/commons/lang3/LocaleUtilsTest.java
b/src/test/java/org/apache/commons/lang3/LocaleUtilsTest.java
index cb665f882..71d3d21c1 100644
--- a/src/test/java/org/apache/commons/lang3/LocaleUtilsTest.java
+++ b/src/test/java/org/apache/commons/lang3/LocaleUtilsTest.java
@@ -261,7 +261,7 @@ void testCountriesByLanguage() {
}
@ParameterizedTest
- @ValueSource(strings = {"x", "abcd", "EN", "e1", "en-US", " "})
+ @ValueSource(strings = {"x", "abcd", "EN", "e1", "en-US", " ", "en", "éé",
"ééé", "eé"})
void testCountriesByLanguageDoesNotCacheInvalidLanguageCode(final String
languageCode) {
final ConcurrentMap<String, List<Locale>> map =
LocaleUtils.getLcToLocalesMap();
assertFalse(map.containsKey(languageCode));
@@ -371,7 +371,7 @@ void testLanguagesByCountry() {
}
@ParameterizedTest
- @ValueSource(strings = {"x", "abcd", "English", "e1", "en-US", " "})
+ @ValueSource(strings = {"x", "abcd", "English", "e1", "en-US", " ", "GB",
"ÉÉ", "GÉ", "ÉB", "١٢٣", "1٢3"})
void testLanguagesByCountryDoesNotCacheInvalidLanguageCode(final String
languageCode) {
final ConcurrentMap<String, List<Locale>> map =
LocaleUtils.getCcToLocalesMap();
assertFalse(map.containsKey(languageCode));
@@ -546,11 +546,11 @@ void testToLocale_2Part() {
@ParameterizedTest
@ValueSource(strings = {
// FULLWIDTH LATIN SMALL LETTER E and N
- "en", "éé", "éé_GB",
+ "en", "éé", "ééé", "eé", "éé_GB", "éé-GB", "éé_GB_POSIX",
// FULLWIDTH LATIN CAPITAL LETTER G and B
- "en_GB", "en_ÉÉ", "en_ÉÉ_POSIX", "_ÉÉ", "_ÉÉ_POSIX",
+ "en_GB", "en_ÉÉ", "en-ÉÉ", "en_ÉÉ_POSIX", "_ÉÉ", "_ÉÉ_POSIX",
"-ÉÉ", "_GÉ", "_ÉB",
// ARABIC-INDIC DIGIT ONE, TWO and THREE
- "en_١٢٣" })
+ "en_١٢٣", "en-١٢٣", "en_1٢3", "en_١٢٣_POSIX" })
void testToLocaleNonAsciiCodes(final String localeString) {
assertIllegalArgumentException(() ->
LocaleUtils.toLocale(localeString), "Should fail code not ASCII: " +
localeString);
}