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

StackOverflow https://stackoverflow.com/questions/1043109

  •  20-08-2019
  •  | 
  •  

Question

C’est 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

  

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

bien qu'il contienne les deux.

Qu'est-ce qui fonctionne mais ce n'est pas 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 donne apparemment pas de réponses.

Je l’utilise sur OpenJDK 6, j’ai donc récupéré les paquetages sources et j’ai installé mon débogueur dans la bibliothèque. Il commence par rechercher jaxb.properties, puis par les propriétés système et, faute de quoi, il tente de créer le contexte par défaut à l'aide de com.sun.internal.xml.bind.v2.ContextFactory. Dans ce document, l’exception est renvoyé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 ici.

ETA :

À en juger par le code source de ContentFactory, j’ai trouvé ici , il s'agit probablement du 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 précédent expérience , je suppose que cela doit être le cas faire avec les mécanismes de chargement de classe du conteneur OSGi dans lequel il s’exécute. Malheureusement, je suis encore un peu hors de ma profondeur ici.

Était-ce utile?

La solution

Bien, cela a pris un peu de temps, mais la réponse n’est pas si surprenante et même pas si compliquée:

JAXB ne peut pas trouver le fichier jaxb.index car, par défaut, newInstance(String) utilise le chargeur de classes du thread actuel (renvoyé par Thread.getContextClassLoader()). Cela ne fonctionne pas dans Felix, car les bundles OSGi et les threads de la structure ont des chargeurs de classes distincts.

La solution consiste à obtenir un chargeur de classes approprié quelque part et à utiliser newInstance(String, ClassLoader). J'ai un chargeur de classe approprié dans l'une des classes du paquetage 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 consulter le chargeur de classes utilisé par l'instance Bundle, mais je ne pouvais pas comprendre comment, et la solution ci-dessus me semble sans danger.

Autres conseils

J'ai rencontré le même problème avec le projet sur lequel je travaille. Après avoir lu http://jaxb.java.net/faq/index.html#classloader , j'ai compris que JAXBContext ne trouve pas le package 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 établir une relation avec JAXB . la classe B est JAXBContext et bMethod est newInstance ()

Si vous connaissez les restrictions relatives aux packages OSGi, vous devez maintenant savoir très bien que le paquet B n'importe pas le package com.c , c'est-à-dire la classe C n'est pas visible dans la classe B et ne peut donc pas instancier C.

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

.

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

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

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 a été créé pour le serveur Glasfish mais fonctionne également avec Tomcat (coché). Avec cette bibliothèque, vous pouvez facilement utiliser JAXB avec des offres OSGI.

Modifier 2:

J'ai déjà eu un problème de chargement de classe étrange similaire dans mon application. Si je l'exécutais en tant qu'application normale, tout allait bien, mais lorsque je l'ai appelé en tant que service Windows, il a commencé à échouer avec ClassNotFoundExceptions. L'analyse a montré que les chargeurs de classes des threads étaient nuls d'une manière ou d'une autre. 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 autorise ce type de modification.

Je viens de rencontrer ce problème. Pour moi, la solution consistait à utiliser le JRE d’IBM au lieu de celui d’Oracle. On dirait que l’implémentation JAXB est plus compatible OSGI dans celui-là.

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

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

Lorsque vous installez et démarrez un ensemble qui exporte le package contenant le fichier jaxb.index ou objectFactory.java

Assurez-vous ensuite que les ensembles important les classes sont arrêtés ou pointant vers le nom du 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)

Pour moi, le problème était qu'un test unitaire qui n'était pas lié au module que j'ai développé ne comportait pas de dépendance pom.xml à mon module. L’UT a tout de même reconnu mon module en raison de la récupération de la liste des packages dans un fichier de configuration partagé.

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

Ma solution était la suivante:

JAXBContext context = JAXBContext.newInstance ( nouvelle classe [] {". mon.package.name "} );

OU

JAXBContext context = 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;
        }
    }

Fonctionne à 100%

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top