Wednesday, November 18, 2009

A Strange behavior about Java Resource Bundle


I am working in a project where I have to load two different property files (for example parent.properties & child.properties ) which are totally have different base name and it should also have inheritance relationship between this two bundle. So that if any keys are not found in child.properties it should get from parent.properties.
When I was analyzing the resource bundle code, I came to know there is method setParent(), this method is used to set which is your parent bundle (something like java super class). For example if we use bundle name called "child_en.properties" the my parent bundle should be "child.properties".
As this method was protected method in ResourceBundle Class, so to use this class I have sub classed my own ResourceBundle class and overridden the setParent Method like below.
public class P4JResourceBundle extends ResourceBundle {
protected void setParent(ResourceBundle parent) {
super.setParent(parent);
}
public void letsChangeParent(String parent){
this.setParent(ResourceBundle.getBundle(parent));
}
public Enumeration getKeys() {
return null;
}
protected Object handleGetObject(String key) {
return null;
}
So after changing the class I have executed with the below method, excepts that it should pick the key from parent.properties file if the key is not present in child.properties file.
public class ResourceBundleExample {
public static void main(String[] args) {
P4JResourceBundle myBundle = new P4JResourceBundle();
myBundle.letsChangeParent("com.passion4java.resourcebundle.parent");
ResourceBundle bundle = myBundle.getBundle("com.passion4java.resourcebundle.child");
System.out.println(bundle.getString("i_am_not_in_child_file"));
}
}
As usual J there is an error thrown saying the key was missing. 
Exception in thread "main" java.util.MissingResourceException: Can't find resource for bundle java.util.PropertyResourceBundle, key i_am_not_in_child_file
at java.util.ResourceBundle.getObject(Unknown Source)
at java.util.ResourceBundle.getString(Unknown Source)
at com.passion4java.resourcebundle.ResourceBundleExample.main(ResourceBundleExample.java:11)
So what's wrong?

I tried to debug the code in the resource bundle class and below code surprised me.
public static final ResourceBundle   getBundle(String   baseName,Locale   locale){
       return getBundleImpl(baseName, locale, getLoader());
}
private static ResourceBundle   getBundleImpl(String   baseName, Locale   locale,
                                            ClassLoader   loader){
         if (baseName == null) {
             throw new NullPointerException  ();
         }

 String   bundleName = baseName;
         String   localeSuffix = locale.toString();
         if (localeSuffix.length() > 0) {
             bundleName += "_" + localeSuffix;
         } else if (locale.getVariant().length() > 0) {
 //new Locale("", "", "VARIANT").toString == ""
 bundleName += "___" + locale.getVariant();
         }
 Locale   defaultLocale = Locale.getDefault();
          Object   lookup = findBundleInCache(loader, bundleName, defaultLocale);
         if (lookup == NOT_FOUND) {
             throwMissingResourceException(baseName, locale);
         } else if (lookup != null) {
             return (ResourceBundle  )lookup;
         }
Object   parent = NOT_FOUND; // **********THIS_LINE_OF_CODE**********
try {
             //locate the root bundle and work toward the desired child
 Object   root = findBundle(loader, baseName, defaultLocale, baseName, null);
             if (root == null) {
                 putBundleInCache(loader, baseName, defaultLocale, NOT_FOUND);
                 root = NOT_FOUND;
             }
…cont
As I was setting the value in setParent() of resource bundle to change the parent resource bundle, but when the bundle are created using ResourceBundle.getInstance(), internally it calls getBundleImpl() which set the parent as "NOT_FOUND" direcly.
I was really confused why the code was setting directly rather than using values from the setter method????
As user of this class this implementation really stops customization which users expects.
Please feel free to comment.

12 comments:

Kili Liam said...

In which Java version?

Mohammed Yousuff said...

i have checked in java 1.5

Kili Liam said...

Seems that it no longer apply to Java6 ... I coulnd't found that code inside the ResourceBundle class ... ;-)

Mohammed Yousuff said...

Thats really great Klli ...But is there any way available in java6 to set the parent ???

Anonymous said...

The parent is normally used for default values based on Locale, eg you have resources_fr_CH which parent is resources_fr which parent is resources. I don't think using setParent is really supported for what you want.

I had exactly the same problem with ResourceBundle a couple of weeks ago (in guts-gui), and my solution was simply to not use it at all!

Kili Liam said...

I think jfpoilpret is correct. You could try to obtain the values you want from one bundle, and if not found, try to obtain it from the other bundle, but that's a solution you probably thought about ... ;-)

Mohammed Yousuff said...

jfpoilpret, i think that may be a best solution :) (just kidding). I was think why sun have given as setParent method and not using it :(

this is a basic concept in OOPS

Mohammed Yousuff said...

Kili Liam, that we may use when we directly handle ResourceBundle class.
I got this problem when i was using fmt:message tag of JSTL...

Their i have no help :)

Kili Liam said...

Oooouuuuuhhhh! That's a different kind of problem ... hope you can solve it.

Mohammed Yousuff said...

Still trying :)

Unknown said...

When I bought my computer and I didn´t know how to use java graphics, so I decided looking for information in a webside and I found an useful information that helped me a lot.. Now I am interested in to do the best investment and I found a webside very useful and interesting called costa rica investment opportunities , I think it´s a very wonderful site.

Generic Viagra said...

I think that it quite interesting to set them with those attributes. It is a pity that it isn't available in java 1.6. I hope that you fix the problem.

Viagra Online Cheap Viagra

Post a Comment

 

This content comes from a hidden element on this page.

The inline option preserves bound JavaScript events and changes, and it puts the content back where it came from when it is closed.
Click me, it will be preserved!

If you try to open a new ColorBox while it is already open, it will update itself with the new content.

Updating Content Example:
Click here to load new content