java - ¿Por qué JAXB no puede encontrar mi jaxb.index cuando se ejecuta dentro de Apache Felix?
osgi apache-felix (10)
Está justo ahí, en el paquete que debería estar indexando. Aún así, cuando llamo
JAXBContext jc = JAXBContext.newInstance("my.package.name");
Obtengo una JAXBException diciendo que
"my.package.name" no contiene ObjectFactory.class o jaxb.index
aunque contiene ambos.
Lo que funciona, pero no es lo que quiero, es
JAXBContext jc = JAXBContext.newInstance(my.package.name.SomeClass.class);
Esta pregunta de varias 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, si no puede 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 qué está sucediendo porque la fuente no está aquí.
ETA :
A juzgar por el código fuente de ContentFactory, que encontré here , esta es probablemente la pieza de código que no funciona como se esperaba:
/**
* 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 experience previous , supongo que esto tiene que ver con los mecanismos de carga de clases del contenedor OSGi en el que se está ejecutando. Desafortunadamente, todavía estoy un poco fuera de mi alcance aquí.
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 eso.
Enfrenté 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 . la clase B es JAXBContext y bMethod es newInstance ()
Si está familiarizado con las restricciones del paquete OSGi, debe estar muy claro ahora que el Bundle B no está importando el paquete com.c, es decir, la clase C no es visible para la clase B, por lo que no puede instanciar 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.
Mi solución fue:
JAXBContext context = JAXBContext.newInstance ( new Class [] {"my.package.name"} );
O
JAXBContext context = JAXBContext.newInstance ( new Class [] {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%
OK, esto requirió bastante investigación, pero la respuesta no es tan sorprendente ni tan complicada:
JAXB no puede encontrar jaxb.index, porque de manera predeterminada, newInstance(String)
usa el cargador de clases del hilo actual (como lo devuelve Thread.getContextClassLoader()
). Esto no funciona dentro de Felix, porque los paquetes OSGi y los subprocesos del framework tienen cargadores de clases separados.
La solución es obtener un cargador de clases adecuado de alguna parte y usar newInstance(String, ClassLoader)
. jaxb.index
un cargador de clases adecuado de una de las clases en el paquete que contiene jaxb.index
, una elección sensata por motivos de flexibilidad probablemente sea ObjectFactory
:
ClassLoader cl = my.package.name.ObjectFactory.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance("my.package.name", cl);
Tal vez también podría obtener el cargador de clases que está utilizando la instancia de Bundle
, pero no pude averiguar cómo y la solución anterior parece segura para mí.
Para el mismo problema, lo resolví poniendo manualmente el paquete en la importación.
Para mí, el problema era que una prueba unitaria que no estaba relacionada con el módulo que he desarrollado no tenía una dependencia en él pom.xml para mi módulo. El UT todavía 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ó 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>
Puede haber otro escenario que puede dar este problema.
Cuando instala e inicia un paquete que exporta el paquete que contiene el jaxb.index o objectFactory.java
Luego, asegúrese de que los paquetes que importan las clases estén detenidos o señalando el nombre correcto del paquete.
También verifique las declaraciones de exportación e importación en el pom.xml
Enfrentando un problema similar en el contenedor servicemix (karaf) osgi
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.
ObjectFactory
esto exitosamente al agregar el paquete de mis clases generadas que contenían ObjectFactory
a la parte <Private-Package>
de la definición de mi paquete, más org.jvnet.jaxb2_commons.*
Editar 2:
Una vez tuve un problema de carga de clases extraño similar en mi aplicación. Si lo ejecutaba 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 clases como nulos de alguna manera. Resolví el problema al configurar SystemClassLoader en los hilos:
// ...
thread.setContextClassLoader(ClassLoader.getSystemClassLoader());
thread.start();
// ...
Sin embargo, no sé si tu contenedor permite este tipo de cambio.