代码之家  ›  专栏  ›  技术社区  ›  James McMahon

为什么在ApacheFelix中运行时jaxb找不到我的jaxb.index?

  •  52
  • James McMahon  · 技术社区  · 15 年前

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

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

    我得到一个JAXB例外

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

    尽管它确实包含这两个元素。

    什么有用,但不完全是我想要的

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

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

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

    埃塔 :

    从ContentFactory的源代码判断,我发现 here ,这可能是一段无法按预期工作的代码:

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

    从我 previous experience 我猜这与运行它的OSGi容器的类加载机制有关。不幸的是,我在这里还是有点力不从心。

    10 回复  |  直到 8 年前
        1
  •  60
  •   James McMahon    15 年前

    好吧,这需要一些挖掘,但答案并不令人惊讶,甚至也不复杂:

    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 实例正在使用,但我不知道如何使用,上面的解决方案对我来说似乎是安全的。

        2
  •  6
  •   Chaits    13 年前

    对于我正在进行的项目,我也面临着类似的问题。读后 http://jaxb.java.net/faq/index.html#classloader 我意识到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 . 类B是JAXBContext,bMethod是NewInstance()。

    如果您熟悉OSGi包限制,那么现在必须非常清楚 B束 未导入包 C C类 不可见 乙类 因此它不能实例化C。

    解决方法是通过 类装载器 到B方法。这个类加载器应该来自 正在导入COM.C的包 . 在这种情况下,我们可以通过 a.class.getClassLoader()类 自从 bundle a正在导入com.c

    希望这是有帮助的。

        3
  •  4
  •   Hart    12 年前

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

        4
  •  1
  •   wierzbiks    11 年前

    如果您在项目中使用Maven,那么只需使用此库:

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

    它是为glasfish服务器创建的,但也与tomcat一起工作(选中)。 使用这个库,您可以轻松地将JAXB与OSGi捆绑包一起使用。

        5
  •  0
  •   akarnokd    15 年前

    编辑2:

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

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

    但不知道您的容器是否允许这种更改。

        6
  •  0
  •   Zoltán    13 年前

    我刚碰到这个问题。对于我来说,解决方案是使用IBM的JRE而不是Oracle的。似乎JAXB实现在这方面更适合OSGi。

        7
  •  0
  •   vikingsteve    11 年前

    我通过添加生成的包含 ObjectFactory <Private-Package> 我的包定义的一部分,加上 org.jvnet.jaxb2_commons.*

        8
  •  0
  •   Naveen Raj    11 年前

    可能还有另一种情况会导致这个问题。

    当您安装并启动一个包时,这个包将导出包含jaxb.index或objectfactory.java的包。

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

    还要检查pom.xml中的export和import语句

    在ServiceMix(Karaf)OSGi容器中面临类似问题

        9
  •  0
  •   Amit Biton    8 年前

    对我来说,问题是与我开发的模块无关的单元测试在it pom.xml中没有对我的模块的依赖性。 由于从共享配置文件中获取包列表,UT仍然可以识别我的模块。

    在运行UT时,它没有编译新模块,因此它没有生成objectfactory.java,因此我收到了错误,即使在编译模块时,我能够看到objectfactory.java。

    添加了以下依赖项:

    <dependency>
        <groupId>com.myCompany</groupId>
        <artifactId>my-module-name</artifactId>
        <version>${project.version}</version>
        <scope>test</scope>
    </dependency>
    
        10
  •  -1
  •   Peter    11 年前

    我的解决方案是:

    JAXBContext context=JAXBContext.newInstance( 新类[]“my.package.name” ;

    JAXBContext context=JAXBContext.newInstance( 新类[]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;
            }
        }
    

    作品100%