6

java.util.ResourceBundle を使用して表示文字列を処理するアプリケーションがあります。一部のプロパティ キーの文字列の配列を返すことができるようにするため、ListResourceBundle を基本型として使用します (それらのほとんどは標準の名前と値のペアです)。

OSGi 環境で ResourceBundle をロードしようとすると、MissingResourceException が発生します。なぜこれが起こるのか分かりません。バンドルを取得しようとする前に、2 つのステートメントでクラス名を解決してクラスの新しいインスタンスを作成できるので、クラスがバンドル内にあることがわかります。ロケール (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 の中に入っているので、リソースが見つかっていることがわかります。クラスがバンドルに含まれていることはわかっています (クラスは内部バンドル クラスに格納されていますが、ローカル クラス ローダーには表示されます)。

私の質問は、私の ResourceBundle を OSGi 内にロードするにはどうすればよいですか? リソース フラグメントを使用したり、文字列名をハードコーディングしたりするよりも、このアプローチを継続することをお勧めします。

解決

ClassLoader に役立つ以下のアドバイスはどちらも役に立ちましたが、私の問題ははるかに単純であることがわかりました。クラス名を取得するために toString() を使用しないでください (知っているべきでしたが、その日は怠惰だったに違いありません)。使用する正しいメソッドは Class.getName() です。

これは、プロパティ ファイルを使用すると、正しく読み込まれることに気付いたことで発見されました。次に、クラス名を入力しても機能しました。既存のクラス参照を使用して正しい名前を取得することにより、テキスト入力エラーを削減しようとしていたときだけでした。

リソース名の文字列バージョンに固執します。これは、JVM が実際に要求されるまでクラスをロードする必要がないことを意味します (現時点で実行することがたくさんあるわけではありません)。

4

2 に答える 2

6

私の頭の上から:検索するクラスローダーがわからないので、ResourceBundle.getBundle(name,locale,classloader)メソッドを試してみてください。ResourceBundleのクラスローダを取得できDefaultDisplayNameProviderますgetClass().getClassLoader()

よろしく、フランク

于 2012-11-28T07:16:20.607 に答える
3

getBundleパラメータを取るメソッドを常に使用する必要がありClassLoaderます。このメソッドの他のバージョンを呼び出すことは、単一の引数を呼び出すことと同じくらい悪いClass.forNameです...つまり、Javaランタイムに、どのクラスローダーにリソースが含まれているかを推測させます。

ResourceBundleがオブジェクトではなくクラスを渡すように強制する理由を本当に理解していません。これは、Java標準ライブラリの貧弱な設計のもう1つの例です。Class

于 2012-11-28T10:56:03.850 に答える