web-dev-qa-db-fra.com

Pourquoi JAXB ne trouve-t-il pas mon jaxb.index lors de l'exécution dans Apache Felix?

C'est juste là, dans le package, qu'il devrait être indexé. Pourtant, quand j'appelle

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

Je reçois une exception JAXBException disant que

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

bien qu'il contienne les deux.

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

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

Cette question de diverses autres personnes apparaît sur de nombreuses listes de diffusion et forums mais ne semble pas obtenir de réponses.

J'exécute cela sur OpenJDK 6, j'ai donc obtenu les packages source et mis mon débogueur dans la bibliothèque. Il commence par rechercher jaxb.properties, puis recherche les propriétés système et à défaut de trouver l'un ou l'autre, il essaie de créer le contexte par défaut à l'aide de com.Sun.internal.xml.bind.v2.ContextFactory. Là-bas, l'exception est levée (à l'intérieur de ContextFactor.createContext(String ClassLoader, Map)), mais je ne vois pas ce qui se passe car la source n'est pas là.

[~ # ~] eta [~ # ~] :

A en juger par le code source de ContentFactory, j'ai trouvé ici , c'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;
    }

D'après mon précédentexpérience , je suppose 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 profondeur ici.

52
Hanno Fietz

OK, cela a pris pas mal de fouilles, mais la réponse n'est pas si surprenante et même pas si compliquée:

JAXB ne trouve pas jaxb.index, car par défaut, newInstance(String) utilise le chargeur de classe du thread actuel (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 consiste à obtenir un chargeur de classe approprié quelque part et à utiliser newInstance(String, ClassLoader). J'ai obtenu un chargeur de classe approprié dans 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 pourriez-vous également accéder au chargeur de classe que l'instance Bundle utilise, mais je n'ai pas pu comprendre comment, et la solution ci-dessus me semble sûre.

60
Hanno Fietz

J'ai rencontré 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 en mesure de trouver le paquet contenant jaxb.index.

Je vais essayer de rendre cela 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 [~ ​​# ~] . la classe B est JAXBContext et bMethod est newInstance ()

Si vous connaissez les restrictions de package OSGi, il doit être très clair maintenant que Bundle B n'est pas en train d'importer le package com .c ie la classe C est non visible à classe B donc il ne peut pas instancier C.

La solution serait de passer un ClassLoader à bMethod. Ce ClassLoader doit provenir d'un bundle qui importe com.c . Dans ce cas, nous pouvons passer A.class.getClassLoader () puisque le bundle A importe com.c

J'espère que cela vous a été utile.

6
Chaits

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

4
Hart

Si vous utilisez maven dans votre projet, utilisez simplement 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 fonctionne également avec Tomcat (coché). Avec cette bibliothèque, vous pouvez facilement utiliser JAXB avec les bundles OSGI.

1
wierzbiks

Je viens de rencontrer ce problème. Pour moi, la solution était d'utiliser le JRE d'IBM au lieu d'Oracle. Il semble que l'implémentation JAXB soit plus conviviale pour OSGI dans celle-ci.

0
Zoltan

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

Lorsque vous installez et démarrez un bundle qui exporte le package qui contient le jaxb.index ou objectFactory.Java

Assurez-vous ensuite que les bundles important les classes sont arrêtés ou pointent vers le nom de package correct.

Vérifiez également les instructions d'exportation et d'importation dans le fichier pom.xml

Problème similaire rencontré dans le conteneur osgi servicemix (karaf)

0
Naveen Raj

J'ai réussi à résoudre ce problème en ajoutant le package de mes classes générées contenant ObjectFactory au <Private-Package> une partie de ma définition d'ensemble, plus org.jvnet.jaxb2_commons.*

0
vikingsteve

Pour moi, le problème était qu'un test unitaire qui n'était pas lié au module que j'ai développé n'avait pas de dépendance pom.xml avec mon module. Le UT a toujours reconnu mon module en raison de la récupération de la liste des packages à partir du fichier de configuration partagé.

Lors de l'exécution de UT il n'a pas compilé le nouveau module donc il n'a pas généré l'ObjectFactory.Java donc j'ai reçu l'erreur même si quand j'ai compilé le module j'ai pu voir l'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>
0
Amit Biton

Modifier 2:

J'ai eu une fois un problème de chargement de classe étrange similaire dans mon application. Si je l'exécute en tant qu'application normale, tout va bien, mais lorsque je l'invoque en tant que service Windows, il commence à échouer avec ClassNotFoundExceptions. L'analyse a montré que les threads ont leurs chargeurs de classe comme null en quelque sorte. J'ai résolu le problème en définissant SystemClassLoader sur les threads:

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

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

0
akarnokd