¿Por qué JAXB no puede encontrar mi jaxb.index cuando se ejecuta dentro de Apache Felix?

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

  •  20-08-2019
  •  | 
  •  

Pregunta

Está justo allí, en el paquete, que debería estar indexando. Aún así, cuando llamo

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

Recibo una JAXBException que dice que

  

" my.package.name " no contiene ObjectFactory.class o jaxb.index

aunque contiene ambos.

Lo que funciona, pero no es exactamente lo que quiero, es

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

Esta pregunta de otras personas aparece en algunas listas de correo y foros, pero aparentemente no obtiene respuestas.

Estoy ejecutando esto en OpenJDK 6, así que obtuve los paquetes fuente y puse mi depurador en la biblioteca. Comienza buscando jaxb.properties, luego busca las propiedades del sistema y, al no encontrarlas, intenta crear el contexto predeterminado utilizando com.sun.internal.xml.bind.v2.ContextFactory. Allí, se lanza la excepción (dentro de ContextFactor.createContext(String ClassLoader, Map)), pero no puedo ver lo que está sucediendo porque la fuente no está aquí.

ETA :

A juzgar por el código fuente de ContentFactory, encontré aquí , este es probablemente el fragmento de código que no funciona según lo previsto:

/**
 * 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 mi anterior experiencia , supongo que esto tiene que hacer con los mecanismos de carga de clase del contenedor OSGi en el que se está ejecutando. Desafortunadamente, todavía estoy un poco fuera de mi profundidad aquí.

¿Fue útil?

Solución

OK, esto requirió bastante investigación, pero la respuesta no es tan sorprendente ni tan complicada:

JAXB no puede encontrar jaxb.index, porque de forma predeterminada, newInstance(String) usa el cargador de clases del hilo actual (tal como lo devuelve Thread.getContextClassLoader()). Esto no funciona dentro de Felix, porque los paquetes OSGi y los hilos del marco tienen cargadores de clases separados.

La solución es obtener un cargador de clases adecuado de alguna parte y usar newInstance(String, ClassLoader). Obtuve un cargador de clases adecuado de una de las clases en el paquete que contiene jaxb.index, una opción sensata por razones de flexibilidad probablemente es ObjectFactory:

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

Tal vez también podría acceder al cargador de clases que está utilizando la instancia Bundle, pero no pude entender cómo, y la solución anterior me parece segura.

Otros consejos

Me enfrenté a un problema similar con el proyecto en el que estoy trabajando. Después de leer http://jaxb.java.net/faq/index.html#classloader me di cuenta de que JAXBContext no puede encontrar el paquete que contiene jaxb.index.

Trataré de hacer esto lo más claro posible.

Tenemos

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

Para relacionarse con JAXB . clase B es JAXBContext y bMethod es newInstance ()

Si está familiarizado con las restricciones del paquete OSGi, debe quedar muy claro ahora que Bundle B no está importando el paquete com.c es decir, clase C es no visible para clase B , por lo tanto, no puede crear una instancia de C.

La solución sería pasar un ClassLoader a bMethod. Este ClassLoader debe provenir de un paquete que está importando com.c . En este caso, podemos pasar A.class.getClassLoader () ya que el paquete A está importando com.c

Espero que esto haya sido útil.

Para el mismo problema, lo resolví colocando manualmente el paquete en la importación.

Si está utilizando maven en su proyecto, simplemente use esta biblioteca:

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

Está creado para el servidor Glasfish pero también funciona con Tomcat (marcado). Con esta biblioteca, puede usar JAXB fácilmente con paquetes OSGI.

Editar 2:

Una vez tuve un problema de carga de clase extraño similar en mi aplicación. Si lo ejecuto como una aplicación normal, todo estaba bien, pero cuando lo invoqué como un servicio de Windows, comenzó a fallar con ClassNotFoundExceptions. El análisis mostró que los hilos tienen sus cargadores de clase como nulos de alguna manera. Resolví el problema configurando SystemClassLoader en los hilos:

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

Sin embargo, no sé si su contenedor permite este tipo de cambio.

Acabo de encontrarme con este problema. Para mí, la solución fue utilizar JRE de IBM en lugar de Oracle. Parece que la implementación de JAXB es más amigable con OSGI en esa.

Resolví esto con éxito agregando el paquete de mis clases generadas que contiene ObjectFactory a la parte <Private-Package> de mi definición de paquete, más org.jvnet.jaxb2_commons.*

Puede haber otro escenario que pueda dar este problema.

Cuando instala e inicia un paquete que exporta el paquete que contiene jaxb.index u objectFactory.java

Luego, asegúrese de que los paquetes que importan las clases están detenidos o señalando el nombre del paquete correcto.

También verifique las declaraciones de exportación e importación en pom.xml

Problema similar enfrentado en el contenedor osgi servicemix (karaf)

Para mí, el problema era que una prueba unitaria que no estaba relacionada con el módulo que desarrollé no tenía una dependencia en pom.xml de mi módulo. La UT aún reconoció mi módulo debido a la obtención de la lista de paquetes del archivo de configuración compartido.

Al ejecutar el UT, no compiló el nuevo módulo, por lo que no generó el ObjectFactory.java, por lo tanto, recibí el error, aunque cuando compilé el módulo pude ver el ObjectFactory.java

agregó la siguiente dependencia:

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

Mi solución fue:

JAXBContext context = JAXBContext.newInstance ( nueva clase [] {" my.package.name "} );

O

JAXBContext context = JAXBContext.newInstance ( nueva clase [] {class.getName ()} );

O

una solución completa:

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

Funciona al 100%

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top