在OSGi包中加载ResourceBundle

时间:2012-11-28 05:21:51

标签: java osgi resourcebundle

我有一个使用java.util.ResourceBundle来处理显示字符串的应用程序。我使用ListResourceBundle作为基类型,因为我希望能够返回一些属性键的字符串数组(大多数是标准名称/值配对)。

当我尝试在OSGi环境中加载ResourceBundle时,我得到一个MissingResourceException。我无法弄清楚为什么会这样。在尝试获取包之前,我可以解析类名并在两个语句中创建类的新实例,因此我知道类在包中。我正在使用区域设置(en_AU)但没有为该区域设置提供特定的类,回退规则应该选择我的默认实现。即使我为语言环境添加了一个类,它也没有解决。

我获取数据的过程是:

服务

public interface NameManager {
   public String getCategoryName(String identifier, Locale locale);
}

的实施
public class OsgiNameManager implements NameManager {
   public String getCategoryName(@Nonnull Identifier category, Locale locale)
   {
      try {
        Collection<ServiceReference> references = (Collection)osgiContext.getServiceReferences(
                 DisplayNameProvider.class, "(namespace=" + category + ")");
        Iterator<ServiceReference> it = references.iterator();
        while ( it.hasNext() ) {
           ServiceReference reference = (ServiceReference)it.next();
           DisplayNameProvider namer = (DisplayNameProvider)osgiContext.getService(reference);
           String name = namer.getCategoryName(category, locale);
           osgiContext.ungetService(reference);

           if (name != null)
              return name;
        }
     }
     catch (InvalidSyntaxException badFormat) {
        LOG.warn("No registered provider for category [" + category + "]" , badFormat);
     }

      return null;
   }
}

这使用自定义服务接口DisplayNameProvider。希望注册名称的模块将其作为服务添加到其激活器中。默认实现采用完全限定资源包名称的类。

public class DefaultDisplayNameProvider implements DisplayNameProvider {
    private Class<?> categoryResolver;
    public String getCategoryName(@Nonnull String category, Locale locale)
    {
       ResourceBundle res = ResourceBundle.getBundle(categoryResolver.toString(), locale);
       try {
          return res.getString(CATEGORY_NAME_KEY);
       }
       catch (MissingResourceException noCols) {
          return null;
       }
    }
 }

(注意,我遗漏了一些字段和静态引用,但这是所做内容的要点)。

我进入DefaultDisplayNameProvider,所以我知道正在找到资源。我知道类在bundle中(它存储在内部bundle类中,但对本地类加载器是可见的)。

我的问题是我需要在OSGi中加载我的ResourceBundle?我宁愿继续使用这种方法,而不是开始使用资源片段或硬编码字符串名称。

解决方案

以下两个有关ClassLoader帮助的建议都很有用,但事实证明我的问题要简单得多。不要使用toString()来获取类名(我应该知道但当天一定是懒惰的)。要使用的正确方法是Class.getName()。

通过注意到如果我使用属性文件它正确加载,就可以发现这一点。然后,如果我输入的类名也在工作。只有当我试图通过使用现有的类引用来减少文本输入错误才能获得正确的名称。

我会坚持使用资源名称的String版本。这意味着JVM不必在实际请求之前加载类(不是说此时要做很多事情)。

2 个答案:

答案 0 :(得分:5)

我的头脑:你可能想尝试ResourceBundle.getBundle(name,locale,classloader)方法,因为ResourceBundle不知道要搜索哪个类加载器。您可以使用DefaultDisplayNameProvider获取getClass().getClassLoader()的类加载器。

问候,弗兰克

答案 1 :(得分:3)

您应该始终使用带有getBundle参数的ClassLoader方法。调用此方法的其他版本与调用单参数Class.forName非常相似...即,您正在强制Java运行时猜测哪个类加载器包含资源。

我真的不明白为什么ResourceBundle强制我们传递类名称而不是Class 对象。这只是Java标准库中糟糕设计的另一个例子,我担心。