mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-27 14:54:52 +02:00
8309622: Re-examine the cache mechanism in BaseLocale
Reviewed-by: dfuchs, rriggs
This commit is contained in:
parent
6f8d351e86
commit
f615ac4bdf
4 changed files with 175 additions and 399 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2023, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2024, 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
|
||||
|
@ -51,6 +51,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||
import java.util.spi.LocaleNameProvider;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import jdk.internal.util.ReferencedKeyMap;
|
||||
import jdk.internal.util.StaticProperty;
|
||||
import jdk.internal.vm.annotation.Stable;
|
||||
|
||||
|
@ -60,7 +61,6 @@ import sun.util.locale.InternalLocaleBuilder;
|
|||
import sun.util.locale.LanguageTag;
|
||||
import sun.util.locale.LocaleExtensions;
|
||||
import sun.util.locale.LocaleMatcher;
|
||||
import sun.util.locale.LocaleObjectCache;
|
||||
import sun.util.locale.LocaleSyntaxException;
|
||||
import sun.util.locale.LocaleUtils;
|
||||
import sun.util.locale.ParseStatus;
|
||||
|
@ -987,29 +987,20 @@ public final class Locale implements Cloneable, Serializable {
|
|||
if (locale != null) {
|
||||
return locale;
|
||||
}
|
||||
return Cache.LOCALECACHE.get(baseloc);
|
||||
return LOCALE_CACHE.computeIfAbsent(baseloc, Locale::createLocale);
|
||||
} else {
|
||||
LocaleKey key = new LocaleKey(baseloc, extensions);
|
||||
return Cache.LOCALECACHE.get(key);
|
||||
return LOCALE_CACHE.computeIfAbsent(key, Locale::createLocale);
|
||||
}
|
||||
}
|
||||
|
||||
private static class Cache extends LocaleObjectCache<Object, Locale> {
|
||||
|
||||
private static final Cache LOCALECACHE = new Cache();
|
||||
|
||||
private Cache() {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Locale createObject(Object key) {
|
||||
if (key instanceof BaseLocale) {
|
||||
return new Locale((BaseLocale)key, null);
|
||||
} else {
|
||||
LocaleKey lk = (LocaleKey)key;
|
||||
return new Locale(lk.base, lk.exts);
|
||||
}
|
||||
}
|
||||
private static final ReferencedKeyMap<Object, Locale> LOCALE_CACHE = ReferencedKeyMap.create(true, ConcurrentHashMap::new);
|
||||
private static Locale createLocale(Object key) {
|
||||
return switch (key) {
|
||||
case BaseLocale base -> new Locale(base, null);
|
||||
case LocaleKey lk -> new Locale(lk.base, lk.exts);
|
||||
default -> throw new InternalError("should not happen");
|
||||
};
|
||||
}
|
||||
|
||||
private static final class LocaleKey {
|
||||
|
|
|
@ -69,9 +69,9 @@ import jdk.internal.access.JavaUtilResourceBundleAccess;
|
|||
import jdk.internal.access.SharedSecrets;
|
||||
import jdk.internal.reflect.CallerSensitive;
|
||||
import jdk.internal.reflect.Reflection;
|
||||
import jdk.internal.util.ReferencedKeyMap;
|
||||
import sun.security.action.GetPropertyAction;
|
||||
import sun.util.locale.BaseLocale;
|
||||
import sun.util.locale.LocaleObjectCache;
|
||||
import sun.util.resources.Bundles;
|
||||
|
||||
import static sun.security.util.SecurityConstants.GET_CLASSLOADER_PERMISSION;
|
||||
|
@ -2867,123 +2867,122 @@ public abstract class ResourceBundle {
|
|||
if (baseName == null) {
|
||||
throw new NullPointerException();
|
||||
}
|
||||
return new ArrayList<>(CANDIDATES_CACHE.get(locale.getBaseLocale()));
|
||||
return new ArrayList<>(CANDIDATES_CACHE.computeIfAbsent(locale.getBaseLocale(),
|
||||
Control::createCandidateList));
|
||||
}
|
||||
|
||||
private static final CandidateListCache CANDIDATES_CACHE = new CandidateListCache();
|
||||
private static final ReferencedKeyMap<BaseLocale, List<Locale>> CANDIDATES_CACHE = ReferencedKeyMap.create(true, ConcurrentHashMap::new);
|
||||
|
||||
private static class CandidateListCache extends LocaleObjectCache<BaseLocale, List<Locale>> {
|
||||
protected List<Locale> createObject(BaseLocale base) {
|
||||
String language = base.getLanguage();
|
||||
String script = base.getScript();
|
||||
String region = base.getRegion();
|
||||
String variant = base.getVariant();
|
||||
private static List<Locale> createCandidateList(BaseLocale base) {
|
||||
String language = base.getLanguage();
|
||||
String script = base.getScript();
|
||||
String region = base.getRegion();
|
||||
String variant = base.getVariant();
|
||||
|
||||
// Special handling for Norwegian
|
||||
boolean isNorwegianBokmal = false;
|
||||
boolean isNorwegianNynorsk = false;
|
||||
if (language.equals("no")) {
|
||||
if (region.equals("NO") && variant.equals("NY")) {
|
||||
variant = "";
|
||||
isNorwegianNynorsk = true;
|
||||
} else {
|
||||
isNorwegianBokmal = true;
|
||||
// Special handling for Norwegian
|
||||
boolean isNorwegianBokmal = false;
|
||||
boolean isNorwegianNynorsk = false;
|
||||
if (language.equals("no")) {
|
||||
if (region.equals("NO") && variant.equals("NY")) {
|
||||
variant = "";
|
||||
isNorwegianNynorsk = true;
|
||||
} else {
|
||||
isNorwegianBokmal = true;
|
||||
}
|
||||
}
|
||||
if (language.equals("nb") || isNorwegianBokmal) {
|
||||
List<Locale> tmpList = getDefaultList("nb", script, region, variant);
|
||||
// Insert a locale replacing "nb" with "no" for every list entry with precedence
|
||||
List<Locale> bokmalList = new ArrayList<>();
|
||||
for (Locale l_nb : tmpList) {
|
||||
var isRoot = l_nb.getLanguage().isEmpty();
|
||||
var l_no = Locale.getInstance(isRoot ? "" : "no",
|
||||
l_nb.getScript(), l_nb.getCountry(), l_nb.getVariant(), null);
|
||||
bokmalList.add(isNorwegianBokmal ? l_no : l_nb);
|
||||
if (isRoot) {
|
||||
break;
|
||||
}
|
||||
bokmalList.add(isNorwegianBokmal ? l_nb : l_no);
|
||||
}
|
||||
return bokmalList;
|
||||
} else if (language.equals("nn") || isNorwegianNynorsk) {
|
||||
// Insert no_NO_NY, no_NO, no after nn
|
||||
List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
|
||||
int idx = nynorskList.size() - 1;
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "", ""));
|
||||
return nynorskList;
|
||||
}
|
||||
// Special handling for Chinese
|
||||
else if (language.equals("zh")) {
|
||||
if (script.isEmpty() && !region.isEmpty()) {
|
||||
// Supply script for users who want to use zh_Hans/zh_Hant
|
||||
// as bundle names (recommended for Java7+)
|
||||
switch (region) {
|
||||
case "TW", "HK", "MO" -> script = "Hant";
|
||||
case "CN", "SG" -> script = "Hans";
|
||||
}
|
||||
}
|
||||
if (language.equals("nb") || isNorwegianBokmal) {
|
||||
List<Locale> tmpList = getDefaultList("nb", script, region, variant);
|
||||
// Insert a locale replacing "nb" with "no" for every list entry with precedence
|
||||
List<Locale> bokmalList = new ArrayList<>();
|
||||
for (Locale l_nb : tmpList) {
|
||||
var isRoot = l_nb.getLanguage().isEmpty();
|
||||
var l_no = Locale.getInstance(isRoot ? "" : "no",
|
||||
l_nb.getScript(), l_nb.getCountry(), l_nb.getVariant(), null);
|
||||
bokmalList.add(isNorwegianBokmal ? l_no : l_nb);
|
||||
if (isRoot) {
|
||||
break;
|
||||
}
|
||||
bokmalList.add(isNorwegianBokmal ? l_nb : l_no);
|
||||
}
|
||||
return bokmalList;
|
||||
} else if (language.equals("nn") || isNorwegianNynorsk) {
|
||||
// Insert no_NO_NY, no_NO, no after nn
|
||||
List<Locale> nynorskList = getDefaultList("nn", script, region, variant);
|
||||
int idx = nynorskList.size() - 1;
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "NO", "NY"));
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "NO", ""));
|
||||
nynorskList.add(idx++, Locale.getInstance("no", "", ""));
|
||||
return nynorskList;
|
||||
}
|
||||
// Special handling for Chinese
|
||||
else if (language.equals("zh")) {
|
||||
if (script.isEmpty() && !region.isEmpty()) {
|
||||
// Supply script for users who want to use zh_Hans/zh_Hant
|
||||
// as bundle names (recommended for Java7+)
|
||||
switch (region) {
|
||||
case "TW", "HK", "MO" -> script = "Hant";
|
||||
case "CN", "SG" -> script = "Hans";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return getDefaultList(language, script, region, variant);
|
||||
}
|
||||
|
||||
private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
|
||||
List<String> variants = null;
|
||||
return getDefaultList(language, script, region, variant);
|
||||
}
|
||||
|
||||
if (!variant.isEmpty()) {
|
||||
variants = new ArrayList<>();
|
||||
int idx = variant.length();
|
||||
while (idx != -1) {
|
||||
variants.add(variant.substring(0, idx));
|
||||
idx = variant.lastIndexOf('_', --idx);
|
||||
private static List<Locale> getDefaultList(String language, String script, String region, String variant) {
|
||||
List<String> variants = null;
|
||||
|
||||
if (!variant.isEmpty()) {
|
||||
variants = new ArrayList<>();
|
||||
int idx = variant.length();
|
||||
while (idx != -1) {
|
||||
variants.add(variant.substring(0, idx));
|
||||
idx = variant.lastIndexOf('_', --idx);
|
||||
}
|
||||
}
|
||||
|
||||
List<Locale> list = new ArrayList<>();
|
||||
|
||||
if (variants != null) {
|
||||
for (String v : variants) {
|
||||
list.add(Locale.getInstance(language, script, region, v, null));
|
||||
}
|
||||
}
|
||||
if (!region.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, script, region, "", null));
|
||||
}
|
||||
if (!script.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, script, "", "", null));
|
||||
// Special handling for Chinese
|
||||
if (language.equals("zh")) {
|
||||
if (region.isEmpty()) {
|
||||
// Supply region(country) for users who still package Chinese
|
||||
// bundles using old convention.
|
||||
switch (script) {
|
||||
case "Hans" -> region = "CN";
|
||||
case "Hant" -> region = "TW";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<Locale> list = new ArrayList<>();
|
||||
|
||||
// With script, after truncating variant, region and script,
|
||||
// start over without script.
|
||||
if (variants != null) {
|
||||
for (String v : variants) {
|
||||
list.add(Locale.getInstance(language, script, region, v, null));
|
||||
list.add(Locale.getInstance(language, "", region, v, null));
|
||||
}
|
||||
}
|
||||
if (!region.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, script, region, "", null));
|
||||
list.add(Locale.getInstance(language, "", region, "", null));
|
||||
}
|
||||
if (!script.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, script, "", "", null));
|
||||
// Special handling for Chinese
|
||||
if (language.equals("zh")) {
|
||||
if (region.isEmpty()) {
|
||||
// Supply region(country) for users who still package Chinese
|
||||
// bundles using old convention.
|
||||
switch (script) {
|
||||
case "Hans" -> region = "CN";
|
||||
case "Hant" -> region = "TW";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// With script, after truncating variant, region and script,
|
||||
// start over without script.
|
||||
if (variants != null) {
|
||||
for (String v : variants) {
|
||||
list.add(Locale.getInstance(language, "", region, v, null));
|
||||
}
|
||||
}
|
||||
if (!region.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, "", region, "", null));
|
||||
}
|
||||
}
|
||||
if (!language.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, "", "", "", null));
|
||||
}
|
||||
// Add root locale at the end
|
||||
list.add(Locale.ROOT);
|
||||
|
||||
return list;
|
||||
}
|
||||
if (!language.isEmpty()) {
|
||||
list.add(Locale.getInstance(language, "", "", "", null));
|
||||
}
|
||||
// Add root locale at the end
|
||||
list.add(Locale.ROOT);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue