summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNarayan Kamath <narayan@google.com>2014-06-25 16:18:38 +0100
committerNarayan Kamath <narayan@google.com>2014-07-23 10:28:42 +0100
commit5c0472fd7c53464e526bb833707551d85dbafec1 (patch)
treec9812c0de3b2c46f4059e07f3179c48df79227ce
parent1debf79647da22cf39dd5b4d0db2e008026fbc60 (diff)
downloadlibcore-5c0472fd7c53464e526bb833707551d85dbafec1.zip
libcore-5c0472fd7c53464e526bb833707551d85dbafec1.tar.gz
libcore-5c0472fd7c53464e526bb833707551d85dbafec1.tar.bz2
Fix handling of invalid locales in Date/DecimalFormatSymbols.
For locales whose language code is "und" we use Locale.ROOT instead. This also fixes two other corner cases : - We were using the wrong locale to fetch timezone strings when the input locale was null. we now use the same locale throughout by making sure we don't perform any subsititutions in LocaleData.get. - Adds a clearer comment about the broken serialization behaviour. bug: 15849709 Change-Id: I95e7eb0ccb7458711038ce9b1c76b3279acda9d6
-rw-r--r--harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java2
-rw-r--r--luni/src/main/java/java/text/DateFormatSymbols.java9
-rw-r--r--luni/src/main/java/java/text/DecimalFormatSymbols.java1
-rw-r--r--luni/src/main/java/libcore/icu/ICU.java2
-rw-r--r--luni/src/main/java/libcore/icu/LocaleData.java25
-rw-r--r--luni/src/main/native/libcore_icu_ICU.cpp22
6 files changed, 38 insertions, 23 deletions
diff --git a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java
index 9fe3681..70e41a2 100644
--- a/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java
+++ b/harmony-tests/src/test/java/org/apache/harmony/tests/java/text/DateFormatSymbolsTest.java
@@ -88,7 +88,7 @@ public class DateFormatSymbolsTest extends junit.framework.TestCase {
Locale locale = new Locale("not exist language", "not exist country");
DateFormatSymbols symbols = DateFormatSymbols.getInstance(locale);
- assertNotNull(symbols);
+ assertEquals(DateFormatSymbols.getInstance(Locale.ROOT), symbols);
}
/**
diff --git a/luni/src/main/java/java/text/DateFormatSymbols.java b/luni/src/main/java/java/text/DateFormatSymbols.java
index 0d33d75..54a1a3f 100644
--- a/luni/src/main/java/java/text/DateFormatSymbols.java
+++ b/luni/src/main/java/java/text/DateFormatSymbols.java
@@ -102,7 +102,7 @@ public class DateFormatSymbols implements Serializable, Cloneable {
* the locale.
*/
public DateFormatSymbols(Locale locale) {
- this.locale = locale;
+ this.locale = LocaleData.mapInvalidAndNullLocales(locale);
this.localPatternChars = SimpleDateFormat.PATTERN_CHARS;
this.localeData = LocaleData.get(locale);
@@ -152,7 +152,12 @@ public class DateFormatSymbols implements Serializable, Cloneable {
private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
ois.defaultReadObject();
- this.localeData = LocaleData.get(locale);
+
+ // NOTE: We don't serialize the locale we were created with, so we can't
+ // get back the localeData object we want. This is broken for callers that
+ // access this field directly (i.e, SimpleDateFormat). We should ideally
+ // have serialized the locale we were created with. See b/16502916.
+ this.localeData = LocaleData.get(Locale.getDefault());
}
private void writeObject(ObjectOutputStream oos) throws IOException {
diff --git a/luni/src/main/java/java/text/DecimalFormatSymbols.java b/luni/src/main/java/java/text/DecimalFormatSymbols.java
index 1611594..6e25c1b 100644
--- a/luni/src/main/java/java/text/DecimalFormatSymbols.java
+++ b/luni/src/main/java/java/text/DecimalFormatSymbols.java
@@ -81,6 +81,7 @@ public class DecimalFormatSymbols implements Cloneable, Serializable {
* the locale.
*/
public DecimalFormatSymbols(Locale locale) {
+ locale = LocaleData.mapInvalidAndNullLocales(locale);
LocaleData localeData = LocaleData.get(locale);
this.zeroDigit = localeData.zeroDigit;
this.digit = '#';
diff --git a/luni/src/main/java/libcore/icu/ICU.java b/luni/src/main/java/libcore/icu/ICU.java
index bb57f49..06e2205 100644
--- a/luni/src/main/java/libcore/icu/ICU.java
+++ b/luni/src/main/java/libcore/icu/ICU.java
@@ -432,7 +432,7 @@ public final class ICU {
private static native String[] getISOLanguagesNative();
private static native String[] getISOCountriesNative();
- static native boolean initLocaleDataNative(String locale, LocaleData result);
+ static native boolean initLocaleDataNative(String languageTag, LocaleData result);
/**
* Takes a BCP-47 language tag (Locale.toLanguageTag()). e.g. en-US, not en_US
diff --git a/luni/src/main/java/libcore/icu/LocaleData.java b/luni/src/main/java/libcore/icu/LocaleData.java
index 845ba32..ec05b53 100644
--- a/luni/src/main/java/libcore/icu/LocaleData.java
+++ b/luni/src/main/java/libcore/icu/LocaleData.java
@@ -112,27 +112,36 @@ public final class LocaleData {
private LocaleData() {
}
+ public static Locale mapInvalidAndNullLocales(Locale locale) {
+ if (locale == null) {
+ return Locale.getDefault();
+ }
+
+ if ("und".equals(locale.toLanguageTag())) {
+ return Locale.ROOT;
+ }
+
+ return locale;
+ }
+
/**
* Returns a shared LocaleData for the given locale.
*/
public static LocaleData get(Locale locale) {
- if (locale == null) {
- locale = Locale.getDefault();
- }
- String localeName = locale.toString();
+ final String languageTag = locale.toLanguageTag();
synchronized (localeDataCache) {
- LocaleData localeData = localeDataCache.get(localeName);
+ LocaleData localeData = localeDataCache.get(languageTag);
if (localeData != null) {
return localeData;
}
}
LocaleData newLocaleData = initLocaleData(locale);
synchronized (localeDataCache) {
- LocaleData localeData = localeDataCache.get(localeName);
+ LocaleData localeData = localeDataCache.get(languageTag);
if (localeData != null) {
return localeData;
}
- localeDataCache.put(localeName, newLocaleData);
+ localeDataCache.put(languageTag, newLocaleData);
return newLocaleData;
}
}
@@ -171,7 +180,7 @@ public final class LocaleData {
private static LocaleData initLocaleData(Locale locale) {
LocaleData localeData = new LocaleData();
- if (!ICU.initLocaleDataNative(locale.toString(), localeData)) {
+ if (!ICU.initLocaleDataNative(locale.toLanguageTag(), localeData)) {
throw new AssertionError("couldn't initialize LocaleData for locale " + locale);
}
diff --git a/luni/src/main/native/libcore_icu_ICU.cpp b/luni/src/main/native/libcore_icu_ICU.cpp
index 733bf38..df26b39 100644
--- a/luni/src/main/native/libcore_icu_ICU.cpp
+++ b/luni/src/main/native/libcore_icu_ICU.cpp
@@ -513,16 +513,16 @@ static bool getYesterdayTodayAndTomorrow(JNIEnv* env, jobject localeData, const
return true;
}
-static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocaleName, jobject localeData) {
- ScopedUtfChars localeName(env, javaLocaleName);
- if (localeName.c_str() == NULL) {
+static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLanguageTag, jobject localeData) {
+ ScopedUtfChars languageTag(env, javaLanguageTag);
+ if (languageTag.c_str() == NULL) {
return JNI_FALSE;
}
- if (localeName.size() >= ULOC_FULLNAME_CAPACITY) {
+ if (languageTag.size() >= ULOC_FULLNAME_CAPACITY) {
return JNI_FALSE; // ICU has a fixed-length limit.
}
- ScopedIcuLocale icuLocale(env, javaLocaleName);
+ ScopedIcuLocale icuLocale(env, javaLanguageTag);
if (!icuLocale.valid()) {
return JNI_FALSE;
}
@@ -530,27 +530,27 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
// Get the DateTimePatterns.
UErrorCode status = U_ZERO_ERROR;
bool foundDateTimePatterns = false;
- for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
+ for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
if (getDateTimePatterns(env, localeData, it.Get())) {
foundDateTimePatterns = true;
break;
}
}
if (!foundDateTimePatterns) {
- ALOGE("Couldn't find ICU DateTimePatterns for %s", localeName.c_str());
+ ALOGE("Couldn't find ICU DateTimePatterns for %s", languageTag.c_str());
return JNI_FALSE;
}
// Get the "Yesterday", "Today", and "Tomorrow" strings.
bool foundYesterdayTodayAndTomorrow = false;
- for (LocaleNameIterator it(localeName.c_str(), status); it.HasNext(); it.Up()) {
+ for (LocaleNameIterator it(icuLocale.locale().getBaseName(), status); it.HasNext(); it.Up()) {
if (getYesterdayTodayAndTomorrow(env, localeData, icuLocale.locale(), it.Get())) {
foundYesterdayTodayAndTomorrow = true;
break;
}
}
if (!foundYesterdayTodayAndTomorrow) {
- ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", localeName.c_str());
+ ALOGE("Couldn't find ICU yesterday/today/tomorrow for %s", languageTag.c_str());
return JNI_FALSE;
}
@@ -621,14 +621,14 @@ static jboolean ICU_initLocaleDataNative(JNIEnv* env, jclass, jstring javaLocale
setNumberPatterns(env, localeData, icuLocale.locale());
setDecimalFormatSymbolsData(env, localeData, icuLocale.locale());
- jstring countryCode = env->NewStringUTF(Locale::createFromName(localeName.c_str()).getCountry());
+ jstring countryCode = env->NewStringUTF(icuLocale.locale().getCountry());
jstring internationalCurrencySymbol = ICU_getCurrencyCode(env, NULL, countryCode);
env->DeleteLocalRef(countryCode);
countryCode = NULL;
jstring currencySymbol = NULL;
if (internationalCurrencySymbol != NULL) {
- currencySymbol = ICU_getCurrencySymbol(env, NULL, javaLocaleName, internationalCurrencySymbol);
+ currencySymbol = ICU_getCurrencySymbol(env, NULL, javaLanguageTag, internationalCurrencySymbol);
} else {
internationalCurrencySymbol = env->NewStringUTF("XXX");
}