在Apache Felix中运行时,为什么JAXB无法find我的jaxb.in​​dex?

它就在那里,它应该是索引的包。 不过,当我打电话

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

我得到一个JAXBException说

“my.package.name”不包含ObjectFactory.class或jaxb.in​​dex

虽然它确实包含两者。

什么工作,但不是我想要的,是

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

来自其他人的这个问题出现在相当多的邮件列表和论坛上,但似乎没有得到答案。

我在OpenJDK 6上运行这个,所以我得到了源码包,并将我的debugging器join到库中。 它首先查找jaxb.properties,然后查找系统属性并找不到,它尝试使用com.sun.internal.xml.bind.v2.ContextFactory创build默认上下文。 在那里,exception被抛出(在ContextFactor.createContext(String ClassLoader, Map) ),但我不明白是怎么回事,因为源不在这里。

ETA

从ContentFactory的源代码来看,我在这里发现,这可能是一段代码无法正常工作:

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

从我之前的 经验来看,我猜测这与运行的OSGi容器的类加载机制有关。不幸的是,在这里我还是有些超出我的深度。

好吧,这花了很多时间,但答案并不令人惊讶,甚至没有那么复杂:

JAXB找不到jaxb.in​​dex,因为默认情况下, newInstance(String)使用当前线程的类加载器(由Thread.getContextClassLoader()返回)。 这在Felix中不起作用,因为OSGi包和框架的线程都有独立的类加载器。

解决的办法是从某处获得合适的类加载器,并使用newInstance(String, ClassLoader) 。 我从包含jaxb.index的类中的一个类中得到了一个合适的类加载器,对于灵活性的原因可能是ObjectFactory

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

也许你也可以在Bundle实例使用的类加载器,但我不知道如何,上面的解决scheme似乎对我来说是安全的。

我正面临与我正在进行的项目类似的问题。 阅读http://jaxb.java.net/faq/index.html#classloader后,我意识到JAXBContext无法find包含jaxb.in​​dex的包。;

我会尽量使这个尽可能清楚。

我们有

 Bundle A -- com.a A.java aMethod() { B.bMethod("com.cC"); } 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 

涉及到JAXBB类是JAXBContext,而bMethod是newInstance()

如果您熟悉OSGi包的限制,那么现在必须非常清楚Bundle B不是导入包com.c,类C类B 不可见 ,因此它不能实例化C.

解决办法是将类加载器传递给bMethod。 这个ClassLoader应该来自一个导入com.c 。 在这种情况下,我们可以传递A.class.getClassLoader(),因为bundle A正在导入com.c

希望这是有帮助的。

对于同样的问题,我通过手动将软件包放入导入来解决此问题。

如果你在你的项目中使用maven,那么就使用这个库:

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

它创buildGlasfish服务器,但也与Tomcat(选中)。 有了这个库,你可以很容易地使用JAXB和OSGI捆绑包。

编辑2:

我的应用程序曾经有类似的奇怪类加载问题。 如果我作为一个正常的应用程序运行它,一切都很好,但是当我作为一个Windows服务调用它时,它开始与ClassNotFoundExceptions失败。 分析表明,这些线程以某种方式将它们的类加载器设置为null。 我通过在线程上设置SystemClassLoader来解决问题:

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

不知道你的容器是否允许这种改变。

我刚刚遇到这个问题。 对我来说,解决scheme是使用IBM的JRE而不是Oracle的。 看起来JAXB的实现在这方面更适合OSGI。

我成功解决了这个问题,把我生成的包含ObjectFactory类包添加到我的包定义的<Private-Package>部分,加上org.jvnet.jaxb2_commons.*

可能会有另一种情况可以解决这个问题。

当您安装并启动一个导出包含jaxb.in​​dex或objectFactory.java的软件包的软件包时

然后请确保导入类的软件包已停止或指向正确的软件包名称。

还要检查pom.xml中的导出和导入语句

在servicemix(karaf)osgi容器面临类似的问题

对我来说,问题是与我开发的模块没有关系的unit testing没有依赖于它的pom.xml到我的模块。 由于从共享configuration文件中获取软件包列表,UT仍然识别出我的模块。

当运行UT时,它并没有编译新的模块,所以它没有生成ObjectFactory.java,因此我收到了错误,即使在编译模块时,我能够看到ObjectFactory.java

添加了以下依赖项:

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

我的解决scheme是:

JAXBContext context = JAXBContext.newInstance( new Class [] {“my.package.name”} );

要么

JAXBContext context = JAXBContext.newInstance( new Class [] {class.getName()} );

要么

完整的解决scheme:

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

工程100%