在Apache Felix中运行时,为什么JAXB无法find我的jaxb.index?
它就在那里,它应该是索引的包。 不过,当我打电话
JAXBContext jc = JAXBContext.newInstance("my.package.name");
我得到一个JAXBException说
“my.package.name”不包含ObjectFactory.class或jaxb.index
虽然它确实包含两者。
什么工作,但不是我想要的,是
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.index,因为默认情况下, 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.index的包。;
我会尽量使这个尽可能清楚。
我们有
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
涉及到JAXB 。 B类是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.index或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%