2009-06-25 3 views
50

Es ist genau dort, in dem Paket, das es indexieren sollte. Dennoch, wenn ich rufeWarum kann JAXB meinen jaxb.index nicht finden, wenn er in Apache Felix läuft?

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

ich einen JAXBException sagen bekommen, dass

"my.package.name" muß nicht ObjectFactory.class oder jaxb.index enthalten

obwohl es enthält beide.

Was funktioniert, ist aber nicht ganz das, was ich will, ist

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

Diese Frage aus verschiedenen anderen Menschen erscheinen ziemlich einige Mailinglisten und Foren, aber scheinbar keine Antworten bekommen.

Ich bin dies auf OpenJDK 6 ausgeführt, also habe ich die Quellpakete und trat mein Debugger in die Bibliothek. Es beginnt mit der Suche nach jaxb.properties, sucht dann nach Systemeigenschaften und findet keine der beiden, es versucht, den Standardkontext mit com.sun.internal.xml.bind.v2.ContextFactory zu erstellen. Dort wird die Exception geworfen (innerhalb ContextFactor.createContext(String ClassLoader, Map)), aber ich kann nicht sehen, was passiert, weil die Quelle nicht hier ist.

ETA:

Geht man von der Quellcode für Content, ich here gefunden, das ist wahrscheinlich das Stück Code, wie beabsichtigt nicht funktioniert:

/** 
* 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; 
    } 

Aus meiner previousexperience, Ich nehme an, dass das mit den Klassenlademechanismen des OSGi-Containers, in dem es läuft, zu tun hat. Leider bin ich hier noch ein wenig überfordert.

+0

Ich meinte bitte die Ausnahme Stack-Trace veröffentlichen. – akarnokd

+0

Der Beitrag wird schon ein wenig lang, aber ich habe bereits den Ursprung der Ausnahme verfolgt, nur oben gepostet. –

Antwort

57

OK, nahm dies durchaus einige graben, aber die Antwort ist nicht so überraschend und nicht einmal so kompliziert:

JAXB nicht jaxb.index finden können, weil standardmäßig newInstance(String) des aktuellen Threads Class Loader verwendet (wie von Thread.getContextClassLoader() zurückgegeben). Dies funktioniert nicht in Felix, da die OSGi-Bundles und die Threads des Frameworks separate Klassenlader haben.

Die Lösung ist, einen geeigneten Klassenlader von irgendwo zu bekommen und newInstance(String, ClassLoader) zu verwenden.Ich bekam einen geeigneten Klassenlader aus einer der Klassen in dem Paket, das wahrscheinlich jaxb.index, eine vernünftige Wahl aus Gründen der Flexibilität enthält, ist ObjectFactory:

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

Vielleicht könnten Sie auch an dem Klassenlader erhalten, dass die Bundle Instanz verwendet , aber ich konnte nicht herausfinden, wie, und die obige Lösung scheint mir sicher.

+1

Dies stellt sich in OSGi-Umgebungen in der Regel als ziemlich unangenehm heraus, wenn Sie Bibliotheken verwenden, die nicht für OSGi entwickelt wurden, und Annahmen über den Klassenlader machen, den sie erhalten. Dieses Problem ist der Grund, warum Leute behaupten, dass Eclipselink der einzige JPA-Anbieter ist, der in OSGi arbeitet (weiß nicht, ob das immer noch zutrifft). –

+1

ContextClassLoader; Wenn Sie den Classloader setzen, sollten Sie zuerst prüfen, ob bereits ein Wert gesetzt ist. Wenn Sie ihn als lokale Variable beibehalten, setzen Sie ihn nach dem Aufruf von JAX in einen finally Block zurück - Sie wissen nicht, was sonst noch Classloader-Hacks verwendet. .. – earcam

+0

Gibt es einen Jira Artikel zu diesem Problem? Wir sind hier gestolpert und ich kann bestätigen, dass die Lösung funktioniert, ich frage mich nur, ob dies ein unbeholfenes Problem von Apache-Felix-Projekt ist – Monachus

0

Edit 2:

Ich hatte einmal ähnlich seltsame Klassenlade Problem in meiner Anwendung. Wenn ich es als normale Anwendung ausführe, war alles in Ordnung, aber als ich es als Windows-Dienst anrief, begann es mit ClassNotFoundExceptions fehlzuschlagen. Die Analyse zeigte, dass die Klassen ihre Klassenlader irgendwie als null haben. Ich löste das Problem, indem die SystemClassLoader Einstellung auf dem Gewinde:

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

Sie nicht wissen, ob Ihr Container obwohl diese Art von Änderung ermöglicht.

+0

Nun, es könnte (ich weiß es nicht), aber es scheint mir, dass es einen Ort geben sollte, an dem ich die Datei ablegen kann, so dass der verwendete Klassenlader sie findet. –

6

Ich konfrontiert ähnliches Problem mit dem Projekt, an dem ich arbeite. Nach dem Lesen http://jaxb.java.net/faq/index.html#classloader erkannte ich, dass JAXBContext das Paket mit jaxb.index nicht finden kann.

Ich werde versuchen, dies so klar wie möglich zu machen.

Wir haben

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 

zu JAXB zu beziehen. Klasse B ist JAXBContext und bMethod ist newInstance()

Wenn Sie mit OSGi-Paket Einschränkungen vertraut sind, dann muss es jetzt sehr klar sein, dass Bundle B importiert nicht Paket com.c dh Klasse C ist nicht sichtbar zu Klasse B daher kann es nicht C. instanziiert

Die Lösung einen Classloader zu bMethod passieren würde. Dieser ClassLoader sollte aus einem Paket stammen, das com.c importiert. In diesem Fall sind wir A.class.getClassLoader() seit Bündel A com.c passieren kann

Hoffnung importiert, das war hilfreich.

0

Ich bin gerade auf dieses Problem gestoßen. Für mich bestand die Lösung darin, IBMs JRE anstelle von Oracle zu verwenden. Scheint so, als wäre die JAXB-Implementierung in diesem OSGI-freundlicher.

4

Für das gleiche Problem, löste ich es, indem Sie das Paket manuell in den Import setzen.

1

Wenn Sie Maven in Ihrem Projekt verwenden, dann diese Bibliothek nur verwenden:

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

Es ist für Glasfish Server erstellt wird, sondern auch mit Tomcat (markiert) arbeiten. Mit dieser Bibliothek können Sie einfach JAXB mit OSGI-Bundles verwenden.

+0

hat super für mich gearbeitet – user617136

0

ich diese erfolgreich gelöst, indem das Paket meiner generierten Klassen Hinzufügen ObjectFactory zum <Private-Package> Teil meiner Bündel-Definition enthält, sowie org.jvnet.jaxb2_commons.*

-1

Meine Lösung war:

JAXBContext context = JAXBContext.newInstance (neu Klasse [] {"my.package.Name "});

ODER

JAXBContext context = JAXBContext.newInstance (neue Klasse [] {class.getName()});

ODER

eine vollständige Lösung:

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; 
     } 
    } 

Works 100%

0

Möglicherweise gibt es ein anderes Szenario, das dieses Problem verursachen kann.

Wenn Sie installieren und ein Bündel beginnen, die das Paket exportieren, die die jaxb.index oder objectFactory.java

Dann stellen Sie sicher, enthält, dass die Bündel, die Klassen werden gestoppt oder Hinweis auf die richtige Paketnamen importieren.

Überprüfen Sie auch die Export- und Import-Anweisungen in der pom.xml

Konfrontiert ähnliches Problem in ServiceMix (karaf) OSGi-Container

0

Für mich war das Problem, dass eine Unit-Test, die nicht mit dem Modul verbunden war dass ich entwickelt habe, hatte keine Abhängigkeit in pom.xml zu meinem Modul. Der UT erkannte mein Modul immer noch, weil die Paketliste aus der gemeinsam genutzten Konfigurationsdatei abgerufen wurde.

Beim Ausführen des UT es nicht das neue Modul kompilieren, damit es nicht die ObjectFactory.java erzeugen habe deshalb ich den Fehler erhalten, auch wenn, wenn ich das Modul kompiliert ich in der Lage war, die ObjectFactory.java

zu sehen

hinzugefügt die folgende Abhängigkeit:

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