This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Patch: ResourceBundle fix and cleanup



(I've also submitted this to classpath via their web interface)

This patch fixes a bug in ResourceBundle which caused the following
program to throw a missing key exception...

import java.util.Locale;
import java.text.DateFormatSymbols;

public class dfs
{
  public static void main(String args[])
  {
    DateFormatSymbols dfs;

    dfs = new DateFormatSymbols (new Locale ("ie", "es"));
    dfs = new DateFormatSymbols (new Locale ("ie", "es"));
  }
}

Assuming there is no gnu.java.locale.LocaleInformation_ie* around, the
first time through DateFormatSymbols.DateFormatSymbols(), the
ResourceBundle.getBundle code would cache
gnu.java.local.LocaleInformation for this locale and then _use_ the
en_US version.  The second time through it simply returns the cached
version, which is definitely the wrong one.

This patch changes ResourceBundle.tryBundle() to only cache exact
matches.  This also has the advantage that you can add locale matching
resource bundles to long running programs by dropping the somewhere in
the classpath.

The second half of the patch removes some redundant method calls and
Locale("", "") allocations.


2001-09-06  Anthony Green  <green@redhat.com>

	* java/util/ResourceBundle.java (tryLocalBundle): Eliminate
	redundant method calls.
	(emptyLocale): New private member.
	(tryBundle): Use emptyLocale.  Remove duplicate code.  Only cache
	exact matches.


Index: libjava/java/util/ResourceBundle.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/util/ResourceBundle.java,v
retrieving revision 1.13
diff -u -p -r1.13 ResourceBundle.java
--- ResourceBundle.java	2001/08/31 21:31:20	1.13
+++ ResourceBundle.java	2001/09/07 03:27:21
@@ -201,8 +201,14 @@ public abstract class ResourceBundle
   private static Map resourceBundleCache = new HashMap();
 
   /**
+   * The `empty' locale is created once in order to optimize
+   * tryBundle().  
+   */
+  private static final Locale emptyLocale = new Locale ("", "");
+
+  /**
    * Tries to load a class or a property file with the specified name.
-   * @param name the name.
+   * @param localizedName the name.
    * @param locale the locale, that must be used exactly.
    * @param classloader the classloader.
    * @param bundle the back up (parent) bundle
@@ -229,21 +235,24 @@ public abstract class ResourceBundle
 	}
     }
 
+    // foundBundle holds exact matches for the localizedName resource
+    // bundle, which may later be cached.
+    ResourceBundle foundBundle = null;
+
     try
       {
 	java.io.InputStream is;
+	final String resourceName =
+	  localizedName.replace('.', '/') + ".properties";
 	if (classloader == null)
-	  is = ClassLoader.getSystemResourceAsStream
-	    (localizedName.replace('.', '/') + ".properties");
+	  is = ClassLoader.getSystemResourceAsStream (resourceName);
 	else
-	  is = classloader.getResourceAsStream
-	    (localizedName.replace('.', '/') + ".properties");
+	  is = classloader.getResourceAsStream (resourceName);
 	if (is != null)
 	  {
-	    ResourceBundle rb = new PropertyResourceBundle(is);
-	    rb.parent = bundle;
-	    rb.locale = locale;
-	    bundle = rb;
+	    foundBundle = new PropertyResourceBundle(is);
+	    foundBundle.parent = bundle;
+	    foundBundle.locale = locale;
 	  }
       }
     catch (java.io.IOException ex)
@@ -257,10 +266,9 @@ public abstract class ResourceBundle
 	  rbClass = Class.forName(localizedName);
 	else
 	  rbClass = classloader.loadClass(localizedName);
-	ResourceBundle rb = (ResourceBundle) rbClass.newInstance();
-	rb.parent = bundle;
-	rb.locale = locale;
-	bundle = rb;
+	foundBundle = (ResourceBundle) rbClass.newInstance();
+	foundBundle.parent = bundle;
+	foundBundle.locale = locale;
       }
     catch (ClassNotFoundException ex)
       {
@@ -274,11 +282,10 @@ public abstract class ResourceBundle
 	// XXX should we also ignore ClassCastException?
       }
 
-    // Put the bundle in the cache
-    if (bundle != null)
-      cache.put(localizedName, new SoftReference(bundle));
+    if (foundBundle != null)
+      cache.put(localizedName, new SoftReference(foundBundle));
 
-    return bundle;
+    return foundBundle;
   }
 
   /**
@@ -298,26 +305,31 @@ public abstract class ResourceBundle
 						     ResourceBundle bundle,
 						     HashMap cache)
   {
-    if (locale.getLanguage().length() > 0)
+    final String language = locale.getLanguage();
+
+    if (language.length() > 0)
       {
-	String name = baseName + "_" + locale.getLanguage();
+	final String country = locale.getCountry();
+	String name = baseName + "_" + language;
 
-	if (locale.getCountry().length() != 0)
+	if (country.length() != 0)
 	  {
 	    bundle = tryBundle(name,
-			       new Locale(locale.getLanguage(), ""),
+			       new Locale(language, ""),
 			       classloader, bundle, cache);
+
+	    name += "_" + country;
 
-	    name += "_" + locale.getCountry();
+	    final String variant = locale.getVariant();
 
-	    if (locale.getVariant().length() != 0)
+	    if (variant.length() != 0)
 	      {
 		bundle = tryBundle(name,
-				   new Locale(locale.getLanguage(),
-					      locale.getCountry()),
+				   new Locale(language,
+					      country),
 				   classloader, bundle, cache);
 
-		name += "_" + locale.getVariant();
+		name += "_" + variant;
 	      }
 	  }
 	bundle = tryBundle(name, locale, classloader, bundle, cache);
@@ -367,7 +379,7 @@ public abstract class ResourceBundle
 	  }
       }
 
-    ResourceBundle baseBundle = tryBundle(baseName, new Locale("", ""),
+    ResourceBundle baseBundle = tryBundle(baseName, emptyLocale,
 					  classLoader, null, cache);
     if (baseBundle == null)
       // JDK says, that if one provides a bundle base_en_UK, one


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]