6

我有一个使用 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 内部,因此我知道正在找到资源。我知道该类在包中(它存储在内部包类中,但对本地类加载器可见)。

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

解决方案

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

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

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

4

2 回答 2

6

突然想到:您可能想尝试该ResourceBundle.getBundle(name,locale,classloader)方法,因为ResourceBundle不知道要搜索哪个类加载器。你可以得到 with 的类加载DefaultDisplayNameProvidergetClass().getClassLoader()

问候,弗兰克

于 2012-11-28T07:16:20.607 回答
3

您应该始终使用getBundleClassLoader参数的方法。调用此方法的其他版本与调用单参数一样糟糕Class.forName……也就是说,您正在强制 Java 运行时猜测哪个类加载器包含资源。

我真的不明白为什么 ResourceBundle 强迫我们传递一个类而不是一个Class 对象。恐怕这只是 Java 标准库中设计不佳的另一个例子。

于 2012-11-28T10:56:03.850 回答