diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java index a178d797270b..3b2a82f90db3 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/BundleContentSubstitutedLocalizationSupport.java @@ -174,11 +174,13 @@ public boolean isNotIncluded(String bundleName) { } @Override - public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale) { - super.prepareBundle(bundleName, bundle, findModule, locale); + public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale, boolean jdkLocale) { + super.prepareBundle(bundleName, bundle, findModule, locale, jdkLocale); /* Initialize ResourceBundle.keySet eagerly */ bundle.keySet(); - this.existingBundles.add(control.toBundleName(bundleName, locale)); + if (!jdkLocale) { + this.existingBundles.add(control.toBundleName(bundleName, locale)); + } } @Override diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java index 514bb53b261b..1868559049d0 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/LocalizationSupport.java @@ -27,9 +27,9 @@ import static com.oracle.svm.util.StringUtil.toDotSeparated; import static com.oracle.svm.util.StringUtil.toSlashSeparated; -import static sun.util.locale.provider.LocaleProviderAdapter.Type.CLDR; import java.lang.reflect.Constructor; +import java.lang.reflect.Field; import java.nio.charset.Charset; import java.util.Collection; import java.util.Collections; @@ -62,8 +62,6 @@ import com.oracle.svm.util.ReflectionUtil; import jdk.graal.compiler.debug.GraalError; -import sun.util.locale.provider.LocaleProviderAdapter; -import sun.util.locale.provider.ResourceBundleBasedAdapter; import sun.util.resources.Bundles; /** @@ -84,6 +82,8 @@ public class LocalizationSupport { public final ResourceBundle.Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_DEFAULT); + private final Bundles.Strategy strategy = getLocaleDataStrategy(); + public final Charset defaultCharset; private final EconomicMap> registeredBundles = EconomicMap.create(); @@ -116,13 +116,23 @@ public Map getBundleContentOf(Object bundle) { throw VMError.unsupportedFeature("Resource bundle lookup must be loaded during native image generation: " + bundle.getClass()); } + private static Bundles.Strategy getLocaleDataStrategy() { + try { + Class localeDataStrategy = ReflectionUtil.lookupClass(false, "sun.util.resources.LocaleData$LocaleDataStrategy"); + Field strategyInstance = ReflectionUtil.lookupField(localeDataStrategy, "INSTANCE"); + return (Bundles.Strategy) strategyInstance.get(null); + } catch (IllegalAccessException e) { + throw VMError.shouldNotReachHere(e); + } + } + @Platforms(Platform.HOSTED_ONLY.class) - public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale) { + public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale, boolean jdkBundle) { /* * Class-based bundle lookup happens on every query, but we don't need to register the * constructor for a property resource bundle since the class lookup will fail. */ - registerRequiredReflectionAndResourcesForBundle(bundleName, Set.of(locale)); + registerRequiredReflectionAndResourcesForBundle(bundleName, Set.of(locale), jdkBundle); if (!(bundle instanceof PropertyResourceBundle)) { registerNullaryConstructor(bundle.getClass()); } @@ -180,49 +190,48 @@ private String getBundleName(String fixedBundleName, Locale locale) { } } - public void registerRequiredReflectionAndResourcesForBundle(String baseName, Collection wantedLocales) { - int i = baseName.lastIndexOf('.'); - if (i > 0) { - String name = baseName.substring(i + 1) + "Provider"; - String providerName = baseName.substring(0, i) + ".spi." + name; - ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), providerName); + public void registerRequiredReflectionAndResourcesForBundle(String baseName, Collection wantedLocales, boolean jdkBundle) { + if (!jdkBundle) { + int i = baseName.lastIndexOf('.'); + if (i > 0) { + String name = baseName.substring(i + 1) + "Provider"; + String providerName = baseName.substring(0, i) + ".spi." + name; + ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), providerName); + } } - ImageSingletons.lookup(RuntimeReflectionSupport.class).registerClassLookup(ConfigurationCondition.alwaysTrue(), baseName); - for (Locale locale : wantedLocales) { - registerRequiredReflectionAndResourcesForBundleAndLocale(baseName, locale); + registerRequiredReflectionAndResourcesForBundleAndLocale(baseName, locale, jdkBundle); } } - public void registerRequiredReflectionAndResourcesForBundleAndLocale(String baseName, Locale baseLocale) { + public void registerRequiredReflectionAndResourcesForBundleAndLocale(String baseName, Locale baseLocale, boolean jdkBundle) { /* * Bundles in the sun.(text|util).resources.cldr packages are loaded with an alternative * strategy which tries parent aliases defined in CLDRBaseLocaleDataMetaInfo.parentLocales. */ - List candidateLocales = isCLDRBundle(baseName) - ? ((ResourceBundleBasedAdapter) LocaleProviderAdapter.forType(CLDR)).getCandidateLocales(baseName, baseLocale) + List candidateLocales = jdkBundle + ? strategy.getCandidateLocales(baseName, baseLocale) : control.getCandidateLocales(baseName, baseLocale); for (Locale locale : candidateLocales) { - String bundleWithLocale = control.toBundleName(baseName, locale); + String bundleWithLocale = jdkBundle ? strategy.toBundleName(baseName, locale) : control.toBundleName(baseName, locale); RuntimeReflection.registerClassLookup(bundleWithLocale); Class bundleClass = ReflectionUtil.lookupClass(true, bundleWithLocale); if (bundleClass != null) { registerNullaryConstructor(bundleClass); } Resources.singleton().registerNegativeQuery(bundleWithLocale.replace('.', '/') + ".properties"); - String otherBundleName = Bundles.toOtherBundleName(baseName, bundleWithLocale, locale); - if (!otherBundleName.equals(bundleWithLocale)) { - RuntimeReflection.registerClassLookup(otherBundleName); + + if (jdkBundle) { + String otherBundleName = Bundles.toOtherBundleName(baseName, bundleWithLocale, locale); + if (!otherBundleName.equals(bundleWithLocale)) { + RuntimeReflection.registerClassLookup(otherBundleName); + } } } } - private boolean isCLDRBundle(String baseName) { - return baseName.startsWith(CLDR.getUtilResourcesPackage()) || baseName.startsWith(CLDR.getTextResourcesPackage()); - } - /** * Template method for subclasses to perform additional tasks. */ diff --git a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java index 5a8a29f4a1b4..b4d81e3f3a91 100644 --- a/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java +++ b/substratevm/src/com.oracle.svm.core/src/com/oracle/svm/core/jdk/localization/OptimizedLocalizationSupport.java @@ -93,7 +93,7 @@ public void prepareClassResourceBundle(String basename, Class bundleClass) { bundleLocaleField.set(bundle, locale); // override in this class does not use findModule - prepareBundle(basename, bundle, null, locale); + prepareBundle(basename, bundle, null, locale, false); } catch (ReflectionUtil.ReflectionUtilError | ReflectiveOperationException e) { throw UserError.abort(e, "Failed to instantiated bundle from class %s, reason %s", bundleClass, e.getCause().getMessage()); } @@ -101,7 +101,7 @@ public void prepareClassResourceBundle(String basename, Class bundleClass) { @Platforms(Platform.HOSTED_ONLY.class) @Override - public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale) { + public void prepareBundle(String bundleName, ResourceBundle bundle, Function> findModule, Locale locale, boolean jdkBundle) { bundle.keySet(); this.resourceBundles.put(Pair.create(bundleName, locale), bundle); } diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java index ac6d541f8c06..2ea99662a445 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/jdk/localization/LocalizationFeature.java @@ -514,7 +514,7 @@ protected void addResourceBundles() { /* Make sure the `bundle` content is complete. */ localeData.setSupplementary((ParallelListResourceBundle) bundle); } - prepareBundle(bundle, locale); + prepareJDKBundle(bundle, locale); } } }); @@ -562,7 +562,7 @@ public void prepareClassResourceBundle(String basename, String className) { Class bundleClass = findClassByName.apply(className); UserError.guarantee(ResourceBundle.class.isAssignableFrom(bundleClass), "%s is not a subclass of ResourceBundle", bundleClass.getName()); trace("Adding class based resource bundle: " + className + " " + bundleClass); - support.registerRequiredReflectionAndResourcesForBundle(basename, Set.of()); + support.registerRequiredReflectionAndResourcesForBundle(basename, Set.of(), false); support.prepareClassResourceBundle(basename, bundleClass); } @@ -609,7 +609,7 @@ private void prepareBundleInternal(String baseName, Collection wantedLoc } somethingFound |= !resourceBundle.isEmpty(); for (ResourceBundle bundle : resourceBundle) { - prepareBundle(baseName, bundle, locale); + prepareBundle(baseName, bundle, locale, false); } } @@ -653,18 +653,17 @@ private void prepareBundleInternal(String baseName, Collection wantedLoc @Platforms(Platform.HOSTED_ONLY.class) protected void prepareNegativeBundle(String baseName, Locale locale) { support.registerBundleLookup(baseName, locale); - support.registerRequiredReflectionAndResourcesForBundleAndLocale(baseName, locale); + support.registerRequiredReflectionAndResourcesForBundleAndLocale(baseName, locale, false); } @Platforms(Platform.HOSTED_ONLY.class) - protected void prepareBundle(ResourceBundle bundle, Locale locale) { + protected void prepareJDKBundle(ResourceBundle bundle, Locale locale) { String baseName = bundle.getBaseBundleName(); - support.registerBundleLookup(baseName, locale); - prepareBundle(baseName, bundle, locale); + prepareBundle(baseName, bundle, locale, true); } @Platforms(Platform.HOSTED_ONLY.class) - private void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale) { + private void prepareBundle(String bundleName, ResourceBundle bundle, Locale locale, boolean jdkBundle) { trace("Adding bundle " + bundleName + ", locale " + locale); /* * Ensure that the bundle contents are loaded. We need to walk the whole bundle parent chain @@ -672,14 +671,14 @@ private void prepareBundle(String bundleName, ResourceBundle bundle, Locale loca */ for (ResourceBundle cur = bundle; cur != null; cur = SharedSecrets.getJavaUtilResourceBundleAccess().getParent(cur)) { /* Register all bundles with their corresponding locales */ - support.prepareBundle(bundleName, cur, this.imageClassLoader::findModule, cur.getLocale()); + support.prepareBundle(bundleName, cur, this.imageClassLoader::findModule, cur.getLocale(), jdkBundle); } /* * Finally, register the requested bundle with requested locale (Requested might be more * specific than the actual bundle locale */ - support.prepareBundle(bundleName, bundle, this.imageClassLoader::findModule, locale); + support.prepareBundle(bundleName, bundle, this.imageClassLoader::findModule, locale, jdkBundle); } @Platforms(Platform.HOSTED_ONLY.class)