FULL PRODUCT VERSION :
java version "1.8.0_51"
Java(TM) SE Runtime Environment (build 1.8.0_51-b16)
Java HotSpot(TM) 64-Bit Server VM (build 25.51-b03, mixed mode)
A DESCRIPTION OF THE PROBLEM :
Even though "he" is the correct ISO language code for Hebrew, if you set your user.language to "he", Java internally converts this to "iw". Then when you load resource bundles, it fails to find the bundle, because it is looking under the wrong filename.
REGRESSION. Last worked in version 7u75
ADDITIONAL REGRESSION INFORMATION:
This issue claims it was fixed for "7": http://bugs.java.com/view_bug.do?bug_id=4778440
It doesn't say *which* build of 7 it was fixed in, but if it was ever fixed, it has regressed again.
I have confirmed the issue occurs in:
- 7u55
- 8u45
- 8u51
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create "Bundle.properties":
a=b
Create "Bundle_he.properties":
a=c
Create "Test.java" using executable test source below.
Then:
$ javac Test.java
$ jar cf test.jar *.class *.properties
$ java -classpath test.jar -Duser.language=he Test
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Output should be "c"
ACTUAL -
Output is "b".
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.util.ResourceBundle;
public class Test {
public static void main(String[] args) {
System.out.println(ResourceBundle.getBundle("Bundle").getString("a"));
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
The obvious workaround is renaming files to use language code "iw", but this complicates resource preparation. Now you have to put specific code into build processes to work around a bug in Java, when everyone else correctly uses "he".
There are workarounds which don't involve doing this:
For your own code, either:
(a) use ICU instead
(b) use the overload of getBundle allowing passing a getControl(), then override methods in there to do the fallback correctly.
If you use third-party libraries, then you can't do either of these, since the code isn't yours. So now your choices are:
(a) convince all the libraries to do the above
(b) if you ship the JRE with your application, install a ResourceBundleControlProvider which returns a ResourceBundle.Control which does the correct fallback.
If you don't ship the JRE with your application *and* you rely on the user's own JRE to run, then it might be possible to exploit another bug in ResourceBundle where it incorrectly caches the bundles. Call getBundle() on all the third-party libraries' bundles, passing your fixed ResourceBundle.Control. ResourceBundle will incorrectly cache this and return it when the third-party library asks for it later. The only downside to this approach is that it relies on the cache never evicting entries.