From 55563c16b5744288c0cb73fde0a07ba9e4d97e09 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 18 Jul 2018 11:10:26 +0200 Subject: [PATCH] StringUtils.parseLocaleString detects variant without country The parseLocale method also turns an empty locale into null now, compatible with parseLocaleString behavior. Includes tests for parsing all available locales on the JVM, checking toString/toLanguageTag equality between parsed and original locale. Issue: SPR-7598 Issue: SPR-16651 (cherry picked from commit cab35aa) --- .../org/springframework/util/StringUtils.java | 18 ++++++++--- .../util/StringUtilsTests.java | 30 +++++++++++++++++-- 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/StringUtils.java b/spring-core/src/main/java/org/springframework/util/StringUtils.java index 7f4daf49a44..379b86f4c68 100644 --- a/spring-core/src/main/java/org/springframework/util/StringUtils.java +++ b/spring-core/src/main/java/org/springframework/util/StringUtils.java @@ -772,19 +772,23 @@ public abstract class StringUtils { public static Locale parseLocale(String localeValue) { String[] tokens = tokenizeLocaleSource(localeValue); if (tokens.length == 1) { - return Locale.forLanguageTag(localeValue); + Locale resolved = Locale.forLanguageTag(localeValue); + return (resolved.getLanguage().length() > 0 ? resolved : null); } return parseLocaleTokens(localeValue, tokens); } /** * Parse the given {@code String} representation into a {@link Locale}. - *

This is the inverse operation of {@link Locale#toString Locale's toString}. + *

For many parsing scenarios, this is an inverse operation of + * {@link Locale#toString Locale's toString}, in a lenient sense. + * This method does not aim for strict {@code Locale} design compliance; + * it is rather specifically tailored for typical Spring parsing needs. + *

Note: This delegate does not accept the BCP 47 language tag format. + * Please use {@link #parseLocale} for lenient parsing of both formats. * @param localeString the locale {@code String}: following {@code Locale's} * {@code toString()} format ("en", "en_UK", etc), also accepting spaces as * separators (as an alternative to underscores) - *

Note: This variant does not accept the BCP 47 language tag format. - * Please use {@link #parseLocale} for lenient parsing of both formats. * @return a corresponding {@code Locale} instance, or {@code null} if none * @throws IllegalArgumentException in case of an invalid locale specification */ @@ -815,6 +819,12 @@ public abstract class StringUtils { variant = trimLeadingCharacter(variant, '_'); } } + + if ("".equals(variant) && country.startsWith("#")) { + variant = country; + country = ""; + } + return (language.length() > 0 ? new Locale(language, country, variant) : null); } diff --git a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java index 80e83aba887..9e382c1849c 100644 --- a/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/util/StringUtilsTests.java @@ -734,9 +734,35 @@ public class StringUtilsTests { assertEquals("Variant containing country code not extracted correctly", variant, locale.getVariant()); } - @Test // SPR-14718 + @Test // SPR-14718, SPR-7598 public void testParseJava7Variant() { - assertEquals("sr_#LATN", StringUtils.parseLocaleString("sr_#LATN").toString()); + assertEquals("sr__#LATN", StringUtils.parseLocaleString("sr__#LATN").toString()); + } + + @Test // SPR-16651 + public void testAvailableLocalesWithLocaleString() { + for (Locale locale : Locale.getAvailableLocales()) { + Locale parsedLocale = StringUtils.parseLocaleString(locale.toString()); + if (parsedLocale == null) { + assertEquals("", locale.getLanguage()); + } + else { + assertEquals(parsedLocale.toString(), locale.toString()); + } + } + } + + @Test // SPR-16651 + public void testAvailableLocalesWithLanguageTag() { + for (Locale locale : Locale.getAvailableLocales()) { + Locale parsedLocale = StringUtils.parseLocale(locale.toLanguageTag()); + if (parsedLocale == null) { + assertEquals("", locale.getLanguage()); + } + else { + assertEquals(parsedLocale.toLanguageTag(), locale.toLanguageTag()); + } + } } }