Java 为什么可以';JAXB在ApacheFelix中运行时是否找到我的JAXB.index?

Java 为什么可以';JAXB在ApacheFelix中运行时是否找到我的JAXB.index?,java,jaxb,osgi,apache-felix,Java,Jaxb,Osgi,Apache Felix,它就在那里,在它应该索引的包中。尽管如此,当我打电话的时候 JAXBContext jc = JAXBContext.newInstance("my.package.name"); 我有一个例外说 “my.package.name”不包含ObjectFactory.class或jaxb.index 尽管它确实包含了这两个方面 什么是有效的,但不是我想要的,是 JAXBContext jc = JAXBContext.newInstance(my.package.name.SomeClass.c

它就在那里,在它应该索引的包中。尽管如此,当我打电话的时候

JAXBContext jc = JAXBContext.newInstance("my.package.name");
我有一个例外说

“my.package.name”不包含ObjectFactory.class或jaxb.index

尽管它确实包含了这两个方面

什么是有效的,但不是我想要的,是

JAXBContext jc = JAXBContext.newInstance(my.package.name.SomeClass.class);
这个来自其他人的问题出现在相当多的邮件列表和论坛上,但似乎没有得到答案

我在OpenJDK 6上运行这个,所以我得到了源代码包并将我的调试器放入库中。它首先查找jaxb.properties,然后查找系统属性,如果找不到,它会尝试使用com.sun.internal.xml.bind.v2.ContextFactory创建默认上下文。在那里,会抛出异常(在
ContextFactor.createContext(String ClassLoader,Map)
中),但我看不到发生了什么,因为源代码不在这里

预计到达时间

从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;
    }
/**
*在指定的包中查找jaxb.index文件并加载其内容
*
*@param pkg要搜索的包名
*@param classLoader要搜索的类加载器
*@返回要加载的类对象列表,如果没有则为null
*如果读取索引文件时出错,@将引发IOException
*如果索引文件中有任何错误,@jaxbeexception
*/
私有静态列表loadIndexedClass(字符串pkg,类加载器类加载器)抛出IOException,JAXBEException{
最终字符串资源=pkg.replace('.','/')+“/jaxb.index”;
final InputStream resourceAsStream=classLoader.getResourceAsStream(资源);
if(resourceAsStream==null){
返回null;
}

从我的经验来看,我猜这与正在运行的OSGi容器的类加载机制有关。不幸的是,我在这里仍然有点不了解。

编辑2:

我曾经在我的应用程序中遇到过类似的奇怪类加载问题。如果我将其作为普通应用程序运行,一切正常,但当我将其作为Windows服务调用时,它开始失败,并出现ClassNotFoundExceptions。分析表明,线程的类加载程序以某种方式为空。我通过设置SystemClassLoade解决了问题螺纹上的r:

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

但不知道您的容器是否允许进行此类更改。

好的,这需要进行一些挖掘,但答案并不令人惊讶,甚至没有那么复杂:

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

也许您还可以找到
实例正在使用的类加载器,但我不知道如何找到,而且上面的解决方案对我来说似乎是安全的。

我在处理的项目中遇到了类似的问题。阅读后,我意识到JAXBContext无法找到包含jaxb.index的包

我会尽量把这件事说清楚

我们有

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
与JAXB相关的类是JAXBContext,方法是newInstance()

如果您熟悉OSGi包限制,那么现在必须非常清楚,包B没有导入包com.c,即类c对于类B不可见,因此它无法实例化c

解决方案是将类加载器传递给b方法。此类加载器应来自导入com.c的捆绑包。在这种情况下,我们可以传递a.class.getClassLoader(),因为捆绑包a导入com.c


希望这是有帮助的。

我刚刚遇到了这个问题。对我来说,解决方案是使用IBM的JRE而不是Oracle的。似乎JAXB实现在这一点上更为OSGI友好。

对于同一个问题,我通过手动将包放入导入来解决它。

如果您在项目中使用maven,那么只需使用图书馆:

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

com.sun.xml.bind
jaxb osgi
2.2.7
它是为Glasfish服务器创建的,但也与Tomcat一起使用(选中)。
有了这个库,您可以轻松地将JAXB与OSGI捆绑包一起使用。

我成功地解决了这个问题,将包含
ObjectFactory
的生成类包添加到捆绑包定义的
部分,再加上
org.jvnet.jaxb2\u commons.
我的解决方案是:

JAXBContext context=JAXBContext.newInstance(newclass[]{“my.package.name”}

JAXBContext context=JAXBContext.newInstance(newclass[]{Class.getName()}

完整的解决方案:

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;
        }
    }
publicstatict反序列化文件(Class\u Class,String\uxml){
试一试{
JAXBContext context=JAXBContext.newInstance(新类[]{u Class});
Unmarshaller um=context.createUnmarshaller();
File File=新文件(_xml);
Object obj=um.unmarshal(文件);
返回类铸件(obj);
}捕获(JAXBEException exc){
返回null;
}
}

100%有效

可能还有另一种情况会导致此问题

当您安装并启动一个包,该包导出包含jaxb.i
<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>