3

NetBeans モジュールアプリケーションで Java ServiceLoader を使用する際に問題があります。これが私がやろうとしていることです(Eclipseの通常のJavaアプリケーションで動作します):

インターフェイスを宣言するinterface.jarがあります。そして、このインターフェースのいくつかの実装を含む implementations.jar があり、すべて spi/META-INF/services/my.package.name.MyInterface ファイルで指定されています (このファイルは implementations.jar にあります)。

クラス ImplementationHandler (さらに別の handler.jar 内) もあり、これにはすべての実装をロードする次のメソッドがあります。

private static List<MyInterface<?>> loadAllImplementations() {
    List<MyInterface<?>> foundImplementations = Lists.newArrayList();
    try {
        for (MyInterface implementation : ServiceLoader.load(MyInterface.class)) {
            foundImplementations.add(implementation);
        }
    } catch (ServiceConfigurationError error) {
        system.out.println("Exception happened");
    }
    return foundImplementations;
}

このコードは、Eclipse の通常のアプリケーション (foundImplementations.size() > 0) のすべての実装を返します。

ただし、NetBeans では、何も見つかりません (foundImplementations.size() == 0)。

詳細:
NetBeans モジュール アプリケーションのソース (オープン ソース、私が作成したものではありません) があり、これを MyInterface 実装のいくつかを使用して拡張する必要があります。interface.jar、implementations.jar、および handler.jar は Eclipse で作成され、別のアプリケーションの一部です。

NetBeans で、新しい実装を使用する必要があるモジュールを開き、3 つの jar ファイルをすべて外部ライブラリとして追加しました (NetBeans はそれらを ext フォルダーにコピーしましたが、これは望ましくありませんが、何もできません。別の myext フォルダーに入れたいと思うかもしれませんが、それはまた別の話です)。次に、すべてを再構築し、実装の 1 つを使用しようとしましたが、見つかりませんでした... 実装を取得するコードは、ImplementationHandler クラスにあり、次のようになります。

public static final <T> MyInteface<T> getByName(String name) {
    for (MyInteface implementation : loadAllImplementations()) {
        if (implementation.getName().equals(name)) {
            return implementation;
        }
    }

    throw new IllegalArgumentException("Unable to find MyInterface class for: " + name);
}

「MyInterface クラスが見つかりません: myImplementationName」という例外が発生しました...

NetBeans に関する私の知識は非常に限られているため、これを機能させるために他に何かする必要があるのではないかと考えていました。

4

3 に答える 3

2

機能させるには、Netbeans に META-INF 内にこのサービス サブフォルダーを作成させる必要があります。やり方はとても簡単ですが、情報には簡単にアクセスできます。

META-INF に何かを追加するには、src/ (ソース ディレクトリ [spi?]) フォルダーにこの名前のフォルダーを作成する必要があります。この場合、services フォルダーも必要です。その中に、サービス インターフェイスと同じ完全修飾名を持つテキスト ファイルを作成します。最終的には、src/META-INF/services/my.package.MyInterface という構造が必要です。

最後に、この [my.package.MyInterface] ファイルのコンテンツには、すべての実装クラス (1 行に 1 つ) がリストされている必要があります。

この設定により、Netbeans はアプリのビルド時に適切な jar を作成します。

この ServiceLoaderの例を見てください。これは完全な例ですが、先ほど説明した Netbeans の統合については説明していません。

于 2011-07-06T13:47:49.197 に答える
0

あきらめて、 ClassLoader をJSPFに置き換えました。これはすぐに使用できるので、NetBeans モジュールとして記述されたサードパーティ プログラムの内部構造や、これがクラス ローダーに与えられたクラスパスに与える影響について知る必要はありません。

于 2010-07-12T12:52:37.793 に答える
0

ServiceLoader.load(Class) は、現在のスレッドのコンテキスト クラス ローダーを使用して、すべての実装をロードします。あなたのケースでは、jar ファイル (implementation.jar) 内の実装クラスがそのクラス ローダーのクラスパスにない可能性があります。

これには、さまざまなアプローチを試す必要がある場合があります。

  • netbeans モジュールのクラスパスにすべての jar が必要な場合もあれば、
  • クラスローダー (おそらく、クラスパスにこれらの jar を持つ URLClassLoader) を作成し、 を使用してServiceLoader.load(Class, ClassLoader)そのクラスローダーを渡す必要がある場合があります。
  • 試すことができる別のオプションがありますが、これについてはわかりません。jar ファイルの仕様では、'implementation.jar' エントリを追加できる Class-Path マニフェスト属性を指定できます。詳細はこちら

ほとんどの場合、handler.jar と implementations.jar は同じクラス ローダーによってロードされません。また、ファイルが ext フォルダーに移動する理由を確認することもできます。

お役に立てれば。

編集:

  • ServiceLoader.load(Class, null)また、システム クラス ローダー (アプリケーションを起動したもの) を使用する を呼び出してみてください。おそらく、そのクラスローダーは、ext ディレクトリにある jar 内のクラスを見つけることができる可能性があります。
于 2010-07-02T14:40:08.807 に答える