ResourceBundle java.util.MissingResourceException 追踪

来源:互联网 发布:java this和super 编辑:程序博客网 时间:2024/06/07 02:28

Caused by:java.util.MissingResourceException: Can't find bundle for base name com.resource.IProN,  locale zh_CN

         atjava.util.ResourceBundle.throwMissingResourceException(Unknown Source)

         atjava.util.ResourceBundle.getBundleImpl(Unknown Source)

         atjava.util.ResourceBundle.getBundle(Unknown Source)

         atsynalarm.resource. IProN.<clinit>(IProN.java:16)

Caused by: java.lang.ClassCastException: com.resource.IProN  cannot be cast to ResourceBundle

         atjava.util.ResourceBundle$Control.newBundle(Unknown Source)

         atjava.util.ResourceBundle.loadBundle(Unknown Source)

         atjava.util.ResourceBundle.findBundle(Unknown Source)

         atjava.util.ResourceBundle.findBundle(Unknown Source)

         atjava.util.ResourceBundle.findBundle(Unknown Source)

         ...3 more

Exception in thread "main"

 

源代码包结构,配置文件和java文件在同一个包下

         com

resource

IProN.java

IProN.properties

 

部分源代码:

Public class IProN{

private static finalString BUNDLE_NAME = "com.resource. IProN ";

private static finalResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME);

  

}

 

在做项目时,用到了java.util.ResourceBundle。程序一直运行正常,但是又一次突然出现了

java.util.MissingResourceException,网上查了半天,仍是毫无头绪。无奈之下,只能先吃饭。回来后突然想到,会不会是我的配置文件出问题了。因为之前做了挺多改动,其中就有配置文件。仔细看了一下,配置文件中有如下的一行:、

menuViewText= \u89c6\u56fe\u

发现多了一个\u,去掉之后,正常运行。

 

但是,是何原因呢?为什么多了个\u就不能正常运行了呢?

 

首先查看java.util.ResourceBundle时如何加载资源文件的。

从API文档中看到。ResourceBundle的bundle name(我的理解就是绑定的资源的文件名)会根据ResourceBundle. getBundle(StringbaseName, …)中的参数baseName 生成。

         简单的说就是会根据参数baseName生成2个bundle name,一个当成类名(class name),另一个当成文件名(properties文件名)。

         既然我的异常时因为多了个\u产生的。那就是说,是在加载我的properties文件时出的问题。

         但是,为什么多了个\u就不能加载了呢?

直接解压java api的源代码,找到ResourceBundle类文件。Java API中还提到,ResourceBundle是通过“ResourceBundle.control.newBundle( )”方法最终生成一个ResourceBundle实例的。所有在ResourceBundle类文件找到newBundle方法,并仔细查看它的实例化过程。发现newBundle是通过API Properties读取配置文件,Properties解析配置文件的过程中,如果发现value中有’\u’存在,Properties会认为,接下来的4个字符是一个unicode编码,且会认为‘\u’后面必须是0-9,a-f,A-F22个字符。否则会抛出IllegalArgumentException异常。

而我的配置文件‘\u’后面是换行符。会导致Properties解析配置文件抛出IllegalArgumentException异常。

现在,问题来了,Properties解析配置文件抛出的是IllegalArgumentException异常。但我的异常信息里没有看到IllegalArgumentException异常,而是MissingResourceException和 ClassCastException,为什么呢?

 

下面是部分源代码(Format就是产生的bundle names)

ResourceBundleloadBundle(CacheKey cacheKey, …  , Stringformat, …){

         ……

int size = formats.size();

for (int i = 0; i < size; i++) {

try {

                  newBundle()

……

} catch (Exception cause) {

                   cacheKey.setCause(cause);

}

if (bundle != null) {

break;

}

}

return bundle;

}

继续研究发现,原来是在ResourceBundle.loadBundle中把IllegalArgumentException捕获,并封装到CacheKey中。

深入研究发现,baseName对应的2个bundle name(一个为类名,一个为配置文件名)的加载都是在newBundle()中完成的。newBundle()会先加载类名,然后再加载配置文件。

我的base name是com.resource.IProN,ResourceBundle会解析成com.resource.IProN 和 com.resource. IProN.properties.

ResourceBundle在加载类名时(com.resource.IProN),发现了这个类(因为存在com.resource.IProN)并成功加载,但是在加载后造型成ResourceBundle不成功,抛出ClassCastException异常,被ResourceBundle.loadBundle捕获,并保存到cacheKey中。然后继续加载properties文件,抛出IllegalArgumentException异常,也被ResourceBundle.loadBundle捕获,但是,并没有保存到cacheKey中(详情请见cacheKey.setCause()方法体)。这时。bundle为null。返回后。在上一层的某个方法中会抛出MissingResourceException异常,并从cacheKey取出之前保存的ClassCastException,当成原因封装到MissingResourceException异常中。

所以,严格来说,我得到的异常其实只有一个异常,就是MissingResourceException,但是这个异常的原因(cause)却被设置成ClassCastException。这显然不是正确的原因,我的原因是因为properties文件加载失败。

 

通过上面分析可知,如果你的资源名(basename)和你得某个类名相同时,ResourceBundle会把你得那个类当成资源加载一次。如果你的那个类不是资源类(也就是说不是继承ResourceBundle),那么会抛出ClassCastException。在接下来的加载properties文件时,如果成功,就会忽略之前的ClassCastException,资源加载成功。如果不成功,则会抛出MissingResourceException异常,把你之前得到的ClassCastException一起显示到控制台上。

 

总结来说,ResourceBundle在加载资源文件时,只会抛出一种异常MissingResourceException,只是说,对于找到类名但造型成ResourceBundle失败的情况,JAVA

API 会把造型异常(ClassCastException)当成MissingResourceException的原因返回。

 

 

 

原创粉丝点击