2009-06-25 14 views
50

このパッケージには、インデックスを作成する必要があります。私はApache Felixの内部でJAXBがjaxb.in​​dexを見つけられないのはなぜですか?

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

を呼び出すときそれでも、私は持つJAXBExceptionはそれが含まれていないものの、

"my.package.name" のdoesntが

で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コンテナのクラスローディングメカニズムと関係があると推測しています。残念ながら、私はここでも少し深いところです。

+0

私は例外スタックトレースを投稿してください。 – akarnokd

+0

投稿はもう少し長くなっていますが、私は既に例外の起源を追跡しました。 –

答えて

57

OK、これはかなりの掘削を取ったが、答えはその驚くべきではないそれさえも複雑ではありません:デフォルトでは、newInstance(String)は、現在のスレッドのクラスローダを使用しているため

JAXBは、jaxb.in​​dexを見つけることができません(Thread.getContextClassLoader()によって返されます)。これは、OSGiバンドルとフレームワークのスレッドが別々のクラスローダーを持っているため、Felix内部では機能しません。

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

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

たぶん、あなたもBundleインスタンスが使用しているクラスローダで得ることができますしかし、私は方法を理解することができず、上記の解決策は私にとって安全だと思われます。

+1

これは、OSGi用に設計されていないライブラリを使用しているときに、OSGi環境ではかなり厄介な問題であることが実際に分かっています。この問題は、人々がEclipselinkがOSGiで動作する唯一のJPAプロバイダであると主張している理由です(それが本当であるかどうかはわかりません)。 –

+1

ContextClassLoader;クラスローダーを設定するときは、まずローカル変数として保持している場合は、すでに設定されているかどうかを確認してから、JAXを呼び出した後finallyブロックでリセットしてください。 .. – earcam

+0

この問題に関連するJira項目はありますか?私たちはここでうんざりして解決策が働いていることを証明することができます。これがapache-felixプロジェクトのawknowledged問題であるかどうか疑問に思っています – Monachus

0

編集2:

私はかつて自分のアプリケーションに似た奇妙なクラスローディング問題を抱えていました。通常のアプリケーションとして実行した場合はすべて正常でしたが、Windowsサービスとして呼び出すと、ClassNotFoundExceptionsで失敗し始めました。分析によると、スレッドはクラスローダーを何とかnullにしています。私はスレッドでにSystemClassLoaderを設定することで、問題を解決:あなたのコンテナはしかしこの変化の種類を許可する場合

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

は知ってはいけません。

+0

さて、それは(私は知らないかもしれませんが)かもしれませんが、使用するクラスローダーが見つけられるようにファイルを置く場所があるはずです。 –

6

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

できるだけ明確にするようにします。

我々はJAXBに関連するには

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 

を持っています。 クラスBを使用すると、OSGiのパッケージの制限に精通している場合、それは、バンドルBクラスCすなわちパッケージcom.cのインポートされていないことを今非常に明確でなければならないたJAXBContextとbMethodのnewInstance(ある)

です見えないクラスB には、したがって、それはC.

をインスタンス化することはできませんされた溶液をbMethodにのClassLoaderを通過することであろう。このClassLoaderはcom30をインポートしているバンドルから取得する必要があります。 バンドルAが、これは役立ちましたcom.c

希望をインポートしているので、このケースでは、A.class.getClassLoader()を渡すことができます。

0

私はこの問題に直面しました。私の場合、ソリューションはOracleの代わりにIBMのJREを使用することでした。 JAXB実装のようにOSGIに優しいと思われます。

4

同じ問題については、手動でパッケージをインポートに入れて解決しました。プロジェクトでMavenを使用している場合は

1

、そしてちょうどこのライブラリを使用します。

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

それはGlasfishサーバー用に作成されただけでなく、Tomcatの(チェック)と協力しています。 このライブラリを使用すると、簡単にJAXBをOSGIバンドルとともに使用できます。

+0

私にとって素晴らしい仕事 – user617136

0

私は成功した私のバンドル定義の<Private-Package>一部にObjectFactoryを含む私の生成されたクラスのパッケージを追加することでこれを解決し、プラスorg.jvnet.jaxb2_commons.*

-1

私の解決策だった:

たJAXBContextコンテキスト= JAXBContext.newInstance(新しいですクラス[] {"my.package。名前 "});

OR

たJAXBContextコンテキスト= JAXBContext.newInstance(新しいクラス[] {class.getName()});

OR

完全なソリューション:

public static <T> T deserializeFile(Class<T> _class, String _xml) { 

     try { 

      JAXBContext context = JAXBContext.newInstance(new Class[]{_class}); 
      Unmarshaller um = context.createUnmarshaller(); 

      File file = new File(_xml); 
      Object obj = um.unmarshal(file); 

      return _class.cast(obj); 

     } catch (JAXBException exc) { 
      return null; 
     } 
    } 

作品100%

0

この問題を引き起こす別のシナリオがあります。

あなたがjaxb.in​​dexまたはobjectFactory.java

その後、クラスをインポートするバンドルが停止したり、正しいパッケージ名を指していることを確認してくださいを含むパッケージをエクスポートするバンドルをインストールして起動します。

はまた私にとってのpom.xml

ServiceMixの(karaf)のOSGiコンテナに直面して、同様の問題

0

にエクスポートとインポート文をチェックし、問題となった、そのモジュールに関連していなかったユニットテスト私が開発したモジュールは、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> 
関連する問題