2009-06-25 5 views
50

C'est juste là, dans le paquet qu'il devrait indexer. Pourtant, quand je l'appellePourquoi JAXB ne trouve-t-il pas mon jaxb.index lors d'une exécution dans Apache Felix?

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

je reçois un JAXBException disant que

"my.package.name" ne marche pas contenir ObjectFactory.class ou jaxb.index

bien qu'il ne contienne tous les deux.

Ce qui fonctionne, mais pas tout à fait ce que je veux, est

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

Cette question de divers autres apparaît sur pas mal de listes de diffusion et forums, mais ne semble pas obtenir des réponses. J'utilise ceci sur OpenJDK 6, donc j'ai récupéré les paquetages source et intégré mon débogueur dans la librairie. Il commence par rechercher jaxb.properties, puis recherche les propriétés du système et, ne trouvant pas non plus, il essaie de créer le contexte par défaut en utilisant com.sun.internal.xml.bind.v2.ContextFactory. Dans là, l'exception est levée (à l'intérieur ContextFactor.createContext(String ClassLoader, Map)), mais je ne peux pas voir ce qui se passe parce que la source n'est pas là.

ETA:

A en juger par le code source pour ContentFactory, je l'ai trouvé here, ce qui est probablement le morceau de code qui ne fonctionne pas comme prévu:

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

De mon previousexperience, Je devine que cela a à voir avec les mécanismes de chargement de classe du conteneur OSGi dans lequel cela fonctionne. Malheureusement, je suis encore un peu hors de ma portée ici.

+0

Je voulais dire s'il vous plaît envoyer la trace de pile d'exception. – akarnokd

+0

Le post est déjà un peu long, mais j'ai déjà suivi l'origine de l'exception, juste posté ci-dessus. –

Répondre

57

OK, cela a pris un certain creusement, mais la réponse est pas surprenant et même pas si compliqué que ça:

JAXB ne peut pas trouver jaxb.index, car par défaut, newInstance(String) utilise le chargeur de classe du thread courant (tel que renvoyé par Thread.getContextClassLoader()). Cela ne fonctionne pas dans Felix, car les bundles OSGi et les threads du framework ont ​​des chargeurs de classe distincts.

La solution est d'obtenir un chargeur de classe approprié de quelque part et d'utiliser newInstance(String, ClassLoader).Je suis un chargeur de classe appropriée de l'une des classes du package qui contient jaxb.index, un choix judicieux pour des raisons de flexibilité est probablement ObjectFactory:

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

Peut-être que vous pourriez aussi obtenir le chargeur de classe que l'instance Bundle utilise , mais je ne pouvais pas comprendre comment, et la solution ci-dessus me semble sûre.

+1

Cela s'avère généralement être un problème assez désagréable dans les environnements OSGi lorsque vous utilisez des bibliothèques qui ne sont pas conçues pour OSGi et faites des suppositions sur le chargeur de classe qu'ils obtiennent. Ce problème est la raison pour laquelle les gens affirment qu'Eclipselink est le seul fournisseur JPA qui fonctionne dans OSGi (ne sait pas si c'est toujours vrai). –

+1

ContextClassLoader; Lors de la définition du classloader, vous devez d'abord vérifier s'il existe déjà une variable locale, puis la réinitialiser dans un bloc finally après votre appel à JAX - vous ne savez pas quoi d'autre utilise les hacks de classloader. .. – earcam

+0

Y a-t-il un élément Jira lié à ce problème? Nous sommes tombés ici et je peux attester que la solution fonctionne, je me demande juste si c'est un problème connu du projet apache-felix – Monachus

0

Edit 2:

J'ai eu étrange problème de chargement de classe similaire dans ma demande. Si je l'exécutais comme une application normale, tout était OK mais quand je l'ai appelé comme un service Windows, il a commencé à échouer avec ClassNotFoundExceptions. L'analyse a montré que les threads ont leurs classloaders comme null en quelque sorte. J'ai résolu le problème en réglant le SystemClassLoader sur les fils:

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

Je ne sais pas si votre conteneur permet ce genre de changement cependant.

+0

Eh bien, il pourrait (je ne sais pas), mais il me semble qu'il devrait y avoir un endroit où je peux mettre le fichier de sorte que le classloader utilisé le trouve. –

6

J'ai fait face à un problème similaire avec le projet sur lequel je travaille. Après avoir lu http://jaxb.java.net/faq/index.html#classloader j'ai réalisé que JAXBContext n'est pas capable de trouver le paquet contenant jaxb.index.

Je vais essayer de rendre ceci aussi clair que possible.

Nous avons

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 

Pour se rapporter à JAXB. classe B est JAXBContext et méthode b est newInstance()

Si vous connaissez des restrictions sur l'emballage OSGi alors il doit être très clair maintenant que Bundle B ne package Importation com.c-à-dire classe C est pas visible à classe B par conséquent, il ne peut pas instancier C.

La solution serait de passer un ClassLoader à méthode b. Ce ClassLoader doit provenir d'un lot qui importe com.c. Dans ce cas, nous pouvons passer A.class.getClassLoader() depuis bundle A importe com.c

espoir cela a été utile.

0

Je viens de rencontrer ce problème. Pour moi, la solution consistait à utiliser le JRE d'IBM au lieu d'Oracle. On dirait que la mise en œuvre de JAXB est plus favorable à OSGI dans celui-ci.

4

Pour le même problème, j'ai résolu le problème en plaçant manuellement le paquet dans l'importation.

1

Si vous utilisez Maven dans votre projet, puis il suffit d'utiliser cette bibliothèque:

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

Il est créé pour le serveur Glasfish mais travaille également avec Tomcat (vérifié). Avec cette bibliothèque, vous pouvez facilement utiliser JAXB avec des bundles OSGI.

+0

a bien fonctionné pour moi – user617136

0

Je résolus avec succès en ajoutant l'ensemble de mes classes générées contenant ObjectFactory à la <Private-Package> partie de ma définition de paquet, plus org.jvnet.jaxb2_commons.*

-1

Ma solution a été:

JAXBContext contexte = JAXBContext.newInstance (nouveau Classe [] {"my.package.nom "});

OU

JAXBContext contexte = JAXBContext.newInstance (nouvelle classe [] {class.getName()});

OU

une solution complète:

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

Il peut y avoir un autre scénario qui peut donner ce problème.

Lorsque vous installez et lancez un paquet qui exportent le paquet contenant le jaxb.index ou objectFactory.java

Alors s'il vous plaît assurez-vous que les faisceaux importatrices les classes sont arrêtés ou pointant vers le nom du package correct.

Vérifiez également l'exportation et les déclarations importation dans le pom.xml

Face problème similaire dans ServiceMix (karaf) conteneur OSGi

0

Pour moi, le problème était qu'un test unitaire qui n'a pas été lié au module que j'ai développé n'a pas eu de dépendance pom.xml dans mon module. L'UT reconnaissait toujours mon module en raison de l'extraction de la liste des paquets à partir du fichier de configuration partagé.

Lors de l'exécution de l'UT, il ne compile pas le nouveau module de sorte qu'il n'a pas généré le ObjectFactory.java donc je recevais l'erreur même si quand je compilé le module, j'ai pu voir le ObjectFactory.java

a ajouté la dépendance suivante:

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