web-dev-qa-db-ja.com

Apache Felix内で実行しているときにJAXBがjaxb.in​​dexを見つけられないのはなぜですか?

パッケージ内で、インデックスを作成する必要があります。それでも、私が電話するとき

_JAXBContext jc = JAXBContext.newInstance("my.package.name");
_

私はそれを言ってJAXBExceptionを取得します

「my.package.name」にObjectFactory.classまたはjaxb.in​​dexが含まれていません

両方が含まれていますが。

うまくいくが、私が望んでいるものではない

_JAXBContext jc = JAXBContext.newInstance(my.package.name.SomeClass.class);
_

他のさまざまな人々からのこの質問は、かなりのメーリングリストやフォーラムに掲載されていますが、回答は得られていないようです。

これをOpenJDK 6で実行しているので、ソースパッケージを取得し、デバッガーをライブラリにステップインしました。 jaxb.propertiesを検索することから開始し、システムプロパティを検索し、見つからない場合、com.Sun.internal.xml.bind.v2.ContextFactoryを使用してデフォルトコンテキストを作成しようとします。そこでは、例外がスローされます(ContextFactor.createContext(String ClassLoader, Map)内)が、ソースがここにないため、何が起こっているのかわかりません。

[〜#〜] eta [〜#〜]

ContentFactoryのソースコードから判断すると、 here が見つかりました。これはおそらく、意図したとおりに動作しないコードの一部です。

_/**
 * Look for jaxb.index file in the specified package and load it's contents
 *
 * @param pkg package name to search in
 * @param classLoader ClassLoader to search in
 * @return a List of Class objects to load, null if there weren't any
 * @throws IOException if there is an error reading the index file
 * @throws JAXBException if there are any errors in the index file
 */
private static List<Class> loadIndexedClasses(String pkg, ClassLoader classLoader) throws IOException, JAXBException {
    final String resource = pkg.replace('.', '/') + "/jaxb.index";
    final InputStream resourceAsStream = classLoader.getResourceAsStream(resource);

    if (resourceAsStream == null) {
        return null;
    }
_

私の previousexperience から、これが実行されているOSGiコンテナのクラスローディングメカニズムに関係していると推測しています。残念ながら、私はまだ少しですここで私の深さから。

52
Hanno Fietz

OK、これはかなり掘り下げましたが、答えはそれほど驚くことではなく、それほど複雑でもありません:

JAXBは、デフォルトでnewInstance(String)が現在のスレッドのクラスローダー(Thread.getContextClassLoader()によって返される)を使用するため、jaxb.in​​dexを見つけることができません。 OSGiバンドルとフレームワークのスレッドには別個のクラスローダーがあるため、Felix内では機能しません。

解決策は、どこかから適切なクラスローダーを取得し、newInstance(String, ClassLoader)を使用することです。 jaxb.indexを含むパッケージのクラスの1つから適切なクラスローダーを取得しました。柔軟性の理由から賢明な選択はおそらくObjectFactoryです。

ClassLoader cl = my.package.name.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("my.package.name", cl);

Bundleインスタンスが使用しているクラスローダーを取得することもできたかもしれませんが、その方法がわかりませんでした。上記の解決策は安全だと思われます。

60
Hanno Fietz

私が取り組んでいるプロジェクトでも同様の問題に直面しました。 http://jaxb.Java.net/faq/index.html#classloader を読んだ後、JAXBContextがjaxb.in​​dexを含むパッケージを見つけることができないことに気付きました。

これをできる限り明確にしようとします。

我々は持っています

Bundle A
   -- com.a
      A.Java
        aMethod()
        {
            B.bMethod("com.c.C");
        }
MANIFEST.MF
Import-Package: com.b, com.c         

Bundle B
   -- com.b
      B.Java
        bmethod(String className)
        {
            Class clazz = Class.forName(className);
        }

Export-Package: com.b

Bundle C
   -- com.c
      C.Java
        c()
        {
            System.out.println("hello i am C");
        }

Export-Package: com.c

関連する[〜#〜] jaxb [〜#〜]クラスBはJAXBContext、bMethodはnewInstance()

OSGiパッケージの制限に精通している場合、Bundle Bがパッケージをインポートしていないことを非常に明確にする必要がありますcom.c ie class C is not visible to class Bしたがって、Cをインスタンス化できません。

解決策は、ClassLoaderをbMethodに渡すことです。このClassLoaderはcom.cをインポートしているバンドルから取得する必要があります。この場合、A.class.getClassLoader()を渡すことができますバンドルAはcom.cをインポートしています

これがお役に立てば幸いです。

6
Chaits

同じ問題について、パッケージを手動でインポートすることで解決しました。

4
Hart

プロジェクトでmavenを使用している場合は、次のライブラリを使用します。

<dependency>
    <groupId>com.Sun.xml.bind</groupId>
    <artifactId>jaxb-osgi</artifactId>
    <version>2.2.7</version>
</dependency>

Glasfishサーバー用に作成されていますが、Tomcatでも動作します(チェック済み)。このライブラリを使用すると、OSGIバンドルでJAXBを簡単に使用できます。

1
wierzbiks

私はちょうどこの問題に遭遇しました。私にとっての解決策は、Oracleの代わりにIBMのJREを使用することでした。 JAXB実装は、その中でよりOSGIフレンドリーであるようです。

0
Zoltan

この問題を引き起こす別のシナリオがあるかもしれません。

Jaxb.in​​dexまたはobjectFactory.Javaを含むパッケージをエクスポートするバンドルをインストールして開始するとき

次に、クラスをインポートするバンドルが停止していること、または正しいパッケージ名を指していることを確認してください。

また、pom.xmlのexportおよびimportステートメントを確認します

Servicemix(karaf)osgiコンテナーで同様の問題に直面

0
Naveen Raj

ObjectFactoryを含む生成されたクラスのパッケージを、バンドル定義の<Private-Package>部分に加えて、org.jvnet.jaxb2_commons.*を追加することで、これを正常に解決しました。

0
vikingsteve

私にとって問題は、私が開発したモジュールに関係のない単体テストがpom.xmlに私のモジュールに依存していないことでした。 UTは、共有構成ファイルからパッケージリストを取得するため、モジュールをまだ認識しています。

UTを実行すると、新しいモジュールがコンパイルされなかったため、ObjectFactory.Javaが生成されなかったため、モジュールをコンパイルしたときにObjectFactoryを確認できたにもかかわらず、エラーが発生しました.Java

次の依存関係を追加しました。

<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>
0
Amit Biton

編集2:

かつて、アプリケーションで同様の奇妙なクラス読み込みの問題が発生しました。通常のアプリケーションとして実行した場合、すべては問題ありませんでしたが、Windowsサービスとして起動すると、ClassNotFoundExceptionsで失敗し始めました。分析の結果、スレッドのクラスローダーはなんとなくnullであることがわかりました。 SystemClassLoaderをスレッドに設定することで問題を解決しました。

// ...
thread.setContextClassLoader(ClassLoader.getSystemClassLoader());
thread.start();
// ...

ただし、コンテナがこの種の変更を許可しているかどうかはわかりません。

0
akarnokd