2012/04/16

ResouseBundle.getBundle(String)在static情境下的問題


如果在一個static block或是static變數中呼叫ResourseBundle.getBundle(String)
在某些特定的情況下可能會造成MissingResourceException

其原因出在官方文件中敘述此method等同於呼叫
getBundle(baseName, Locale.getDefault(), this.getClass().getClassLoader())

問題在於this.getClass().getClassLoader()的部分,this在static內是取不到參照的
而實際上底層的實作是透過下列這段code取得ClassLoader
/*
 * Automatic determination of the ClassLoader to be used to load
 * resources on behalf of the client.  N.B. The client is getLoader's
 * caller's caller.
 */
private static ClassLoader getLoader() {
    Class[] stack = getClassContext();
    /* Magic number 2 identifies our caller's caller */
    Class c = stack[2];
    ClassLoader cl = (c == null) ? null : c.getClassLoader();
    if (cl == null) {
        // When the caller's loader is the boot class loader, cl is null
        // here. In that case, ClassLoader.getSystemClassLoader() may
        // return the same class loader that the application is
        // using. We therefore use a wrapper ClassLoader to create a
        // separate scope for bundles loaded on behalf of the Java
        // runtime so that these bundles cannot be returned from the
        // cache to the application (5048280).
        cl = RBClassLoader.INSTANCE;
    }
    return cl;
}

這樣會導致你取得的ClassLoader跟預期的結果不同
進而取不到目標resource

若要在static中使用ResourceBundle.getBundle(String)最好的方式還是自行呼叫
ResourseBundle.getBundle(baseName, Locale.getDefault(), [TargetClass].class.getClassLoader())