Patch: FYI: ResourceBundle fixes
Tom Tromey
tromey@redhat.com
Mon Sep 23 11:13:00 GMT 2002
I'm checking this in.
First, ResourceBundle.getBundle required that the base bundle exist.
However, this is not required by the 1.4 docs. Also, the JDK doesn't
do this. This is PR 6576.
Second, ResourceBundle.tryLocalBundle wasn't searching all the
possibilities. For instance if we're using Locale("","US"), then we
didn't search for "<base>__US.properties". The JDK does this too.
Third, ResourceBundle didn't cache the result if it failed to find a
given bundle. This causes a slowdown as reported a long time ago from
Jeff Sturm. My testing indicates that the JDK caches this, so we can
safely do it.
I tested this by running it against our test suite, including Mauve.
There were no regressions.
I'm also going to check this in to Classpath.
Tom
Index: ChangeLog
from Tom Tromey <tromey@redhat.com>
Fix for PR libgcj/6576:
* java/util/ResourceBundle.java (tryBundle): Cache `null' if we
didn't find a given bundle.
(getBundle): Don't require base bundle.
(setParent): Removed old comment.
(tryLocalBundle): Try components even if preceding components were
empty.
Index: java/util/ResourceBundle.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/ResourceBundle.java,v
retrieving revision 1.19
diff -u -r1.19 ResourceBundle.java
--- java/util/ResourceBundle.java 9 May 2002 23:41:42 -0000 1.19
+++ java/util/ResourceBundle.java 23 Sep 2002 17:47:45 -0000
@@ -65,7 +65,7 @@
baseName_<i>def. language</i>
baseName</pre>
*
- * <p>A bundle is backed up by less specific bundles (omiting variant, country
+ * <p>A bundle is backed up by less specific bundles (omitting variant, country
* or language). But it is not backed up by the default language locale.
*
* <p>If you provide a bundle for a given locale, say
@@ -239,7 +239,6 @@
*/
protected void setParent(ResourceBundle parent)
{
- // Shall we ignore the old parent?
this.parent = parent;
}
@@ -362,42 +361,59 @@
cache = new HashMap();
resourceBundleCache.put(classLoader, cache);
}
- else
+ else if (cache.containsKey(name))
{
- Reference ref = (Reference) cache.get(name);
- if (ref != null)
- {
- ResourceBundle rb = (ResourceBundle) ref.get();
- if (rb != null)
- // rb should already have the right parent, except if
- // something very strange happened.
- return rb;
- }
+ Reference ref = (Reference) cache.get(name);
+ ResourceBundle result = null;
+ // If REF is null, that means that we added a `null' value to
+ // the hash map. That means we failed to find the bundle
+ // previously, and we cached that fact. The JDK does this, so
+ // it must be ok.
+ if (ref == null)
+ throw new MissingResourceException("Bundle " + baseName
+ + " not found",
+ baseName, "");
+ else
+ {
+ ResourceBundle rb = (ResourceBundle) ref.get();
+ if (rb != null)
+ {
+ // RB should already have the right parent, except if
+ // something very strange happened.
+ return rb;
+ }
+ // If RB is null, then we previously found it but it was
+ // collected. So we try again.
+ }
}
+ // It is ok if this returns null. We aren't required to have the
+ // base bundle.
ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
classLoader, null, cache);
- if (baseBundle == null)
- // JDK says, that if one provides a bundle base_en_UK, one
- // must also provide the bundles base_en and base.
- // This implies that if there is no bundle for base, there
- // is no bundle at all.
- throw new MissingResourceException("Bundle " + baseName + " not found",
- baseName, "");
- // Now use the default locale.
+ // Now use our locale, followed by the default locale. We only
+ // need to try the default locale if our locale is different, and
+ // if our locale failed to yield a result other than the base
+ // bundle.
ResourceBundle bundle = tryLocalBundle(baseName, locale,
classLoader, baseBundle, cache);
if (bundle == baseBundle && !locale.equals(Locale.getDefault()))
- bundle = tryLocalBundle(baseName, Locale.getDefault(),
- classLoader, baseBundle, cache);
+ {
+ bundle = tryLocalBundle(baseName, Locale.getDefault(),
+ classLoader, baseBundle, cache);
+ // We need to record that the argument locale maps to the
+ // bundle we just found. If we didn't find a bundle, record
+ // that instead.
+ if (bundle == null)
+ cache.put(name, null);
+ else
+ cache.put(name, new SoftReference(bundle));
+ }
- // Check whether baseName_locale has been loaded; if not, map the
- // "baseName" bundle to "baseName_locale" to avoid retrying to load
- // baseName_locale.
- Reference ref = (Reference) cache.get(name);
- if (ref == null)
- cache.put(name, new SoftReference(bundle));
+ if (bundle == null)
+ throw new MissingResourceException("Bundle " + baseName + " not found",
+ baseName, "");
return bundle;
}
@@ -440,15 +456,28 @@
HashMap cache)
{
// First look into the cache.
- // XXX We should remove cleared references from the cache.
- Reference ref = (Reference) cache.get(localizedName);
- if (ref != null)
- {
- ResourceBundle rb = (ResourceBundle) ref.get();
- if (rb != null)
- // rb should already have the right parent, except if
- // something very strange happened.
- return rb;
+ if (cache.containsKey(localizedName))
+ {
+ Reference ref = (Reference) cache.get(localizedName);
+ ResourceBundle result = null;
+ // If REF is null, that means that we added a `null' value to
+ // the hash map. That means we failed to find the bundle
+ // previously, and we cached that fact. The JDK does this, so
+ // it must be ok.
+ if (ref == null)
+ return null;
+ else
+ {
+ ResourceBundle rb = (ResourceBundle) ref.get();
+ if (rb != null)
+ {
+ // RB should already have the right parent, except if
+ // something very strange happened.
+ return rb;
+ }
+ // If RB is null, then we previously found it but it was
+ // collected. So we try again.
+ }
}
// foundBundle holds exact matches for the localizedName resource
@@ -470,30 +499,38 @@
// ignore them all
}
if (foundBundle == null)
- try
- {
- InputStream is;
- final String resourceName
- = localizedName.replace('.', '/') + ".properties";
- if (classloader == null)
- is = ClassLoader.getSystemResourceAsStream(resourceName);
- else
- is = classloader.getResourceAsStream(resourceName);
- if (is != null)
- {
- foundBundle = new PropertyResourceBundle(is);
- foundBundle.parent = bundle;
- foundBundle.locale = locale;
- }
- }
- catch (IOException ex)
- {
- }
+ {
+ try
+ {
+ InputStream is;
+ final String resourceName
+ = localizedName.replace('.', '/') + ".properties";
+ if (classloader == null)
+ is = ClassLoader.getSystemResourceAsStream(resourceName);
+ else
+ is = classloader.getResourceAsStream(resourceName);
+ if (is != null)
+ {
+ foundBundle = new PropertyResourceBundle(is);
+ foundBundle.parent = bundle;
+ foundBundle.locale = locale;
+ }
+ }
+ catch (IOException ex)
+ {
+ }
+ }
- if (foundBundle != null)
+ // Put the result into the hash table. If we didn't find anything
+ // here, we record our parent bundle. If we record `null' that means
+ // nothing, not even the base, was found.
+ if (foundBundle == null)
+ foundBundle = bundle;
+ if (foundBundle == null)
+ cache.put(localizedName, null);
+ else
cache.put(localizedName, new SoftReference(foundBundle));
-
- return foundBundle != null ? foundBundle : bundle;
+ return foundBundle;
}
/**
@@ -501,45 +538,50 @@
* locales with the same language.
*
* @param name the name
- * @param locale the locale, that must be used exactly
+ * @param locale the locale
* @param classloader the classloader
* @param bundle the backup (parent) bundle
* @return the resource bundle if it was loaded, otherwise the backup
*/
private static final ResourceBundle tryLocalBundle(String baseName,
- Locale locale,
+ Locale locale,
ClassLoader classloader,
ResourceBundle bundle,
HashMap cache)
{
final String language = locale.getLanguage();
+ final String country = locale.getCountry();
+ final String variant = locale.getVariant();
+
StringBuffer sb = new StringBuffer(60);
+ sb.append(baseName);
+ sb.append('_');
if (language.length() > 0)
{
- final String country = locale.getCountry();
- sb.append(baseName).append('_').append(language);
- String name = sb.toString();
-
- if (country.length() != 0)
- {
- bundle = tryBundle(name, new Locale(language),
- classloader, bundle, cache);
- sb.append('_').append(country);
- name = sb.toString();
-
- final String variant = locale.getVariant();
-
- if (variant.length() != 0)
- {
- bundle = tryBundle(name, new Locale(language, country),
- classloader, bundle, cache);
- sb.append('_').append(variant);
- name = sb.toString();
- }
- }
- bundle = tryBundle(name, locale, classloader, bundle, cache);
+ sb.append(language);
+ bundle = tryBundle(sb.toString(), new Locale(language),
+ classloader, bundle, cache);
}
+ // If LANGUAGE was empty, we still need to try the other
+ // components, and the `_' is required.
+ sb.append('_');
+
+ if (country.length() > 0)
+ {
+ sb.append(country);
+ bundle = tryBundle(sb.toString(), new Locale(language, country),
+ classloader, bundle, cache);
+ }
+ sb.append('_');
+
+ if (variant.length() > 0)
+ {
+ sb.append(variant);
+ bundle = tryBundle(sb.toString(), locale,
+ classloader, bundle, cache);
+ }
+
return bundle;
}
-} // class ResourceBundle
+}
More information about the Java-patches
mailing list