8232871: Host Locale Provider on Mac does not return translated values of Japanese calendar
authornaoto
Thu, 07 Nov 2019 11:34:01 -0800
changeset 58972 dc998d4a227e
parent 58969 a4430bb9f97d
child 58973 291775bcf35d
8232871: Host Locale Provider on Mac does not return translated values of Japanese calendar Reviewed-by: bchristi
src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java
src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c
test/jdk/java/util/Locale/LocaleProviders.java
test/jdk/java/util/Locale/LocaleProvidersRun.java
--- a/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Thu Nov 07 10:06:04 2019 -0800
+++ b/src/java.base/macosx/classes/sun/util/locale/provider/HostLocaleProviderAdapterImpl.java	Thu Nov 07 11:34:01 2019 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,6 +33,7 @@
 import java.text.spi.NumberFormatProvider;
 import java.util.Collections;
 import java.util.Calendar;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Map;
@@ -550,15 +551,33 @@
             }
 
             @Override
-            public String getDisplayName(String calType, int field, int value,
-                                         int style, Locale locale) {
-                return null;
+            public String getDisplayName(String calendarType, int field,
+                                         int value, int style, Locale locale) {
+                String[] names = getCalendarDisplayStrings(locale.toLanguageTag(),
+                        field, style);
+                if (names != null && value >= 0 && value < names.length) {
+                    return names[value];
+                } else {
+                    return null;
+                }
             }
 
             @Override
-            public Map<String, Integer> getDisplayNames(String calType,
-                                         int field, int style, Locale locale) {
-                return null;
+            public Map<String, Integer> getDisplayNames(String calendarType,
+                                                        int field, int style, Locale locale) {
+                Map<String, Integer> map = null;
+                String[] names = getCalendarDisplayStrings(locale.toLanguageTag(),
+                        field, style);
+                if (names != null) {
+                    map = new HashMap<>((int)Math.ceil(names.length / 0.75));
+                    for (int value = 0; value < names.length; value++) {
+                        if (names[value] != null) {
+                            map.put(names[value], value);
+                        }
+                    }
+                    map = map.isEmpty() ? null : map;
+                }
+                return map;
             }
         };
     }
@@ -901,6 +920,9 @@
     // For CalendarDataProvider
     private static native int getCalendarInt(String langTag, int type);
 
+    // For CalendarNameProvider
+    private static native String[] getCalendarDisplayStrings(String langTag, int field, int style);
+
     // For Locale/CurrencyNameProvider
     private static native String getDisplayString(String langTag, int key, String value);
 
--- a/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c	Thu Nov 07 10:06:04 2019 -0800
+++ b/src/java.base/macosx/native/libjava/HostLocaleProviderAdapter_md.c	Thu Nov 07 11:34:01 2019 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,11 +30,20 @@
 
 #define BUFLEN 256
 
+// java.util.Calendar constants
+#define CALENDAR_FIELD_ERA              0           // Calendar.ERA
+#define CALENDAR_FIELD_DAY_OF_WEEK      7           // Calendar.DAY_OF_WEEK
+#define CALENDAR_FIELD_AM_PM            9           // Calendar.AM_PM
+#define JAPANESE_MEIJI_INDEX            232
+
 static CFDateFormatterStyle convertDateFormatterStyle(jint javaStyle);
 static CFNumberFormatterStyle convertNumberFormatterStyle(jint javaStyle);
 static void copyArrayElements(JNIEnv *env, CFArrayRef cfarray, jobjectArray jarray, CFIndex sindex, int dindex, int count);
 static jstring getNumberSymbolString(JNIEnv *env, jstring jlangtag, jstring jdefault, CFStringRef type);
 static jchar getNumberSymbolChar(JNIEnv *env, jstring jlangtag, jchar jdefault, CFStringRef type);
+jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint style, jobjectArray eras);
+jobjectArray getWeekdaysImpl(JNIEnv *env, jclass cls, jstring jlangtag, jint style, jobjectArray wdays);
+jobjectArray getAmPmImpl(JNIEnv *env, jclass cls, jstring jlangtag, jint style, jobjectArray ampms);
 
 // from java_props_macosx.c
 extern char * getMacOSXLocale(int cat);
@@ -131,41 +140,7 @@
  */
 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getAmPmStrings
   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray ampms) {
-    CFLocaleRef cflocale = CFLocaleCopyCurrent();
-    jstring tmp_string;
-    if (cflocale != NULL) {
-        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
-                                                  cflocale,
-                                                  kCFDateFormatterFullStyle,
-                                                  kCFDateFormatterFullStyle);
-        if (df != NULL) {
-            char buf[BUFLEN];
-            CFStringRef amStr = CFDateFormatterCopyProperty(df, kCFDateFormatterAMSymbol);
-            if (amStr != NULL) {
-                CFStringGetCString(amStr, buf, BUFLEN, kCFStringEncodingUTF8);
-                CFRelease(amStr);
-                tmp_string = (*env)->NewStringUTF(env, buf);
-                if (tmp_string != NULL) {
-                    (*env)->SetObjectArrayElement(env, ampms, 0, tmp_string);
-                }
-            }
-            if (!(*env)->ExceptionCheck(env)){
-                CFStringRef pmStr = CFDateFormatterCopyProperty(df, kCFDateFormatterPMSymbol);
-                if (pmStr != NULL) {
-                    CFStringGetCString(pmStr, buf, BUFLEN, kCFStringEncodingUTF8);
-                    CFRelease(pmStr);
-                    tmp_string = (*env)->NewStringUTF(env, buf);
-                    if (tmp_string != NULL) {
-                        (*env)->SetObjectArrayElement(env, ampms, 1, tmp_string);
-                    }
-                }
-            }
-            CFRelease(df);
-        }
-        CFRelease(cflocale);
-    }
-
-    return ampms;
+      return getAmPmImpl(env, cls, jlangtag, 0, ampms);
 }
 
 /*
@@ -175,24 +150,7 @@
  */
 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getEras
   (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray eras) {
-    CFLocaleRef cflocale = CFLocaleCopyCurrent();
-    if (cflocale != NULL) {
-        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
-                                                  cflocale,
-                                                  kCFDateFormatterFullStyle,
-                                                  kCFDateFormatterFullStyle);
-        if (df != NULL) {
-            CFArrayRef cferas = CFDateFormatterCopyProperty(df, kCFDateFormatterEraSymbols);
-            if (cferas != NULL) {
-                copyArrayElements(env, cferas, eras, 0, 0, CFArrayGetCount(cferas));
-                CFRelease(cferas);
-            }
-            CFRelease(df);
-        }
-        CFRelease(cflocale);
-    }
-
-    return eras;
+    return getErasImpl(env, jlangtag, 0, eras);
 }
 
 /*
@@ -255,25 +213,8 @@
  * Signature: (Ljava/lang/String;[Ljava/lang/String;)[Ljava/lang/String;
  */
 JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getWeekdays
-  (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
-    CFLocaleRef cflocale = CFLocaleCopyCurrent();
-    if (cflocale != NULL) {
-        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
-                                                  cflocale,
-                                                  kCFDateFormatterFullStyle,
-                                                  kCFDateFormatterFullStyle);
-        if (df != NULL) {
-            CFArrayRef cfwdays = CFDateFormatterCopyProperty(df, kCFDateFormatterWeekdaySymbols);
-            if (cfwdays != NULL) {
-                copyArrayElements(env, cfwdays, wdays, 0, 1, CFArrayGetCount(cfwdays));
-                CFRelease(cfwdays);
-            }
-            CFRelease(df);
-        }
-        CFRelease(cflocale);
-    }
-
-    return wdays;
+    (JNIEnv *env, jclass cls, jstring jlangtag, jobjectArray wdays) {
+    return getWeekdaysImpl(env, cls, jlangtag, 0, wdays);
 }
 
 /*
@@ -508,6 +449,29 @@
 
 /*
  * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
+ * Method:    getCalendarDisplayStrings
+ * Signature: (Ljava/lang/String;III)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_sun_util_locale_provider_HostLocaleProviderAdapterImpl_getCalendarDisplayStrings
+  (JNIEnv *env, jclass cls, jstring jlangtag, jint field, jint style) {
+    switch (field) {
+    case CALENDAR_FIELD_ERA:
+        return getErasImpl(env, jlangtag, style, NULL);
+
+    case CALENDAR_FIELD_DAY_OF_WEEK:
+        return getWeekdaysImpl(env, cls, jlangtag, style, NULL);
+
+    case CALENDAR_FIELD_AM_PM:
+        return getAmPmImpl(env, cls, jlangtag, style, NULL);
+
+    default:
+        // not supported
+        return NULL;
+    }
+}
+
+/*
+ * Class:     sun_util_locale_provider_HostLocaleProviderAdapterImpl
  * Method:    getDisplayString
  * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String;
  */
@@ -725,3 +689,104 @@
 
     return ret;
 }
+
+jobjectArray getErasImpl(JNIEnv *env, jstring jlangtag, jint style, jobjectArray eras) {
+    jobjectArray ret = eras;
+    CFLocaleRef cflocale = CFLocaleCopyCurrent();
+    if (cflocale != NULL) {
+        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
+                                                  cflocale,
+                                                  convertDateFormatterStyle(style),
+                                                  convertDateFormatterStyle(style));
+        if (df != NULL) {
+            CFArrayRef cferas = CFDateFormatterCopyProperty(df, kCFDateFormatterEraSymbols);
+            if (cferas != NULL) {
+                int eraCount = CFArrayGetCount(cferas);
+
+                if (eras == NULL) {
+                    ret = (*env)->NewObjectArray(env, (jsize)eraCount,
+                        (*env)->FindClass(env, "java/lang/String"), NULL);
+                }
+                CFTypeRef cal = CFLocaleGetValue(cflocale, kCFLocaleCalendarIdentifier);
+                int sindex = cal == kCFJapaneseCalendar ? JAPANESE_MEIJI_INDEX : 0;
+                int dindex = cal == kCFJapaneseCalendar ? 1 : 0; // 0 is "BeforeMeiji" in JCal
+                copyArrayElements(env, cferas, ret, sindex, dindex, eraCount - sindex);
+                CFRelease(cferas);
+            }
+            CFRelease(df);
+        }
+        CFRelease(cflocale);
+    }
+
+    return ret;
+}
+
+jobjectArray getWeekdaysImpl(JNIEnv *env, jclass cls, jstring jlangtag, jint style, jobjectArray wdays) {
+    jobjectArray ret = wdays;
+    CFLocaleRef cflocale = CFLocaleCopyCurrent();
+    if (cflocale != NULL) {
+        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
+                                                  cflocale,
+                                                  convertDateFormatterStyle(style),
+                                                  convertDateFormatterStyle(style));
+        if (df != NULL) {
+            CFArrayRef cfwdays = CFDateFormatterCopyProperty(df, kCFDateFormatterWeekdaySymbols);
+            if (cfwdays != NULL) {
+                int dayCount = CFArrayGetCount(cfwdays);
+
+                if (wdays == NULL) {
+                    ret = (*env)->NewObjectArray(env, dayCount + 1,
+                        (*env)->FindClass(env, "java/lang/String"), NULL);
+                }
+                copyArrayElements(env, cfwdays, ret, 0, 1, dayCount);
+                CFRelease(cfwdays);
+            }
+            CFRelease(df);
+        }
+        CFRelease(cflocale);
+    }
+
+    return ret;
+}
+
+jobjectArray getAmPmImpl(JNIEnv *env, jclass cls, jstring jlangtag, jint style, jobjectArray ampms) {
+    CFLocaleRef cflocale = CFLocaleCopyCurrent();
+    jstring tmp_string;
+    if (cflocale != NULL) {
+        CFDateFormatterRef df = CFDateFormatterCreate(kCFAllocatorDefault,
+                                                  cflocale,
+                                                  convertDateFormatterStyle(style),
+                                                  convertDateFormatterStyle(style));
+        if (df != NULL) {
+            char buf[BUFLEN];
+            if (ampms == NULL) {
+                ampms = (*env)->NewObjectArray(env, 2,
+                    (*env)->FindClass(env, "java/lang/String"), NULL);
+            }
+            CFStringRef amStr = CFDateFormatterCopyProperty(df, kCFDateFormatterAMSymbol);
+            if (amStr != NULL) {
+                CFStringGetCString(amStr, buf, BUFLEN, kCFStringEncodingUTF8);
+                CFRelease(amStr);
+                tmp_string = (*env)->NewStringUTF(env, buf);
+                if (tmp_string != NULL) {
+                    (*env)->SetObjectArrayElement(env, ampms, 0, tmp_string);
+                }
+            }
+            if (!(*env)->ExceptionCheck(env)){
+                CFStringRef pmStr = CFDateFormatterCopyProperty(df, kCFDateFormatterPMSymbol);
+                if (pmStr != NULL) {
+                    CFStringGetCString(pmStr, buf, BUFLEN, kCFStringEncodingUTF8);
+                    CFRelease(pmStr);
+                    tmp_string = (*env)->NewStringUTF(env, buf);
+                    if (tmp_string != NULL) {
+                        (*env)->SetObjectArrayElement(env, ampms, 1, tmp_string);
+                    }
+                }
+            }
+            CFRelease(df);
+        }
+        CFRelease(cflocale);
+    }
+
+    return ampms;
+}
--- a/test/jdk/java/util/Locale/LocaleProviders.java	Thu Nov 07 10:06:04 2019 -0800
+++ b/test/jdk/java/util/Locale/LocaleProviders.java	Thu Nov 07 11:34:01 2019 -0800
@@ -29,6 +29,7 @@
 public class LocaleProviders {
 
     private static final boolean IS_WINDOWS = System.getProperty("os.name").startsWith("Windows");
+    private static final boolean IS_MAC = System.getProperty("os.name").startsWith("Mac");
 
     public static void main(String[] args) {
         String methodName = args[0];
@@ -82,6 +83,10 @@
                 bug8228465Test();
                 break;
 
+            case "bug8232871Test":
+                bug8232871Test();
+                break;
+
             default:
                 throw new RuntimeException("Test method '"+methodName+"' not found.");
         }
@@ -286,4 +291,40 @@
             }
         }
     }
+
+    static void bug8232871Test() {
+        LocaleProviderAdapter lda = LocaleProviderAdapter.getAdapter(CalendarNameProvider.class, Locale.US);
+        LocaleProviderAdapter.Type type = lda.getAdapterType();
+        var lang = Locale.getDefault().getLanguage();
+        var cal = Calendar.getInstance();
+        var calType = cal.getCalendarType();
+        var expected = "\u4ee4\u548c1\u5e745\u67081\u65e5 \u6c34\u66dc\u65e5 \u5348\u524d0:00:00 \u30a2\u30e1\u30ea\u30ab\u592a\u5e73\u6d0b\u590f\u6642\u9593";
+
+        if (type == LocaleProviderAdapter.Type.HOST &&
+            IS_MAC &&
+            lang.equals("ja") &&
+            calType.equals("japanese")) {
+            cal.set(1, 4, 1, 0, 0, 0);
+            cal.setTimeZone(TimeZone.getTimeZone("America/Los_Angeles"));
+            DateFormat df = DateFormat.getDateTimeInstance(DateFormat.FULL, DateFormat.FULL,
+                            Locale.JAPAN);
+            df.setCalendar(cal);
+            var result = df.format(cal.getTime());
+            if (result.equals(expected)) {
+                System.out.println("bug8232871Test succeeded.");
+            } else {
+                throw new RuntimeException(
+                            "Japanese calendar names mismatch. result: " +
+                            result +
+                            ", expected: " +
+                            expected);
+            }
+        } else {
+            System.out.println("Test ignored. Either :-\n" +
+                "OS is not macOS, or\n" +
+                "provider is not HOST: " + type + ", or\n" +
+                "Language is not Japanese: " + lang + ", or\n" +
+                "native calendar is not JapaneseCalendar: " + calType);
+        }
+    }
 }
--- a/test/jdk/java/util/Locale/LocaleProvidersRun.java	Thu Nov 07 10:06:04 2019 -0800
+++ b/test/jdk/java/util/Locale/LocaleProvidersRun.java	Thu Nov 07 11:34:01 2019 -0800
@@ -25,7 +25,7 @@
  * @test
  * @bug 6336885 7196799 7197573 7198834 8000245 8000615 8001440 8008577
  *      8010666 8013086 8013233 8013903 8015960 8028771 8054482 8062006
- *      8150432 8215913 8220227 8228465
+ *      8150432 8215913 8220227 8228465 8232871
  * @summary tests for "java.locale.providers" system property
  * @library /test/lib
  * @build LocaleProviders
@@ -156,6 +156,9 @@
 
         //testing 8228465 fix. (Windows only)
         testRun("HOST", "bug8228465Test", "", "", "");
+
+        //testing 8232871 fix. (macOS only)
+        testRun("HOST", "bug8232871Test", "", "", "");
     }
 
     private static void testRun(String prefList, String methodName,