【问题标题】:Why can't JAXB find my jaxb.index when running inside Apache Felix?为什么在 Apache Felix 中运行时 JAXB 找不到我的 jaxb.in​​dex?
【发布时间】:2010-11-05 19:11:04
【问题描述】:

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

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 上运行它,所以我得到了源包并将我的调试器步进到库中。它首先查找 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;
    }

从我的previousexperience 来看,我猜测这与运行它的 OSGi 容器的类加载机制有关。不幸的是,我在这里仍然有点不够深入。

【问题讨论】:

  • 我的意思是请发布异常堆栈跟踪。
  • 帖子已经有点长了,但我已经追踪到异常的来源,刚刚在上面发布。

标签: java jaxb osgi apache-felix


【解决方案1】:

对我来说,问题是与我开发的模块无关的单元测试在 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>

【讨论】:

    【解决方案2】:

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

    当您安装并启动一个捆绑包时,该捆绑包会导出包含 jaxb.in​​dex 或 objectFactory.java 的包

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

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

    在 servicemix(karaf) osgi 容器中遇到类似问题

    【讨论】:

      【解决方案3】:

      我的解决方案是:

      JAXBContext 上下文 = JAXBContext.newInstance(new Class[]{"my.package.name"});

      JAXBContext 上下文 = JAXBContext.newInstance(new Class[]{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% 有效

      【讨论】:

        【解决方案4】:

        我通过将包含ObjectFactory 的生成类的包添加到我的包定义的&lt;Private-Package&gt; 部分以及org.jvnet.jaxb2_commons.* 来成功解决了这个问题

        【讨论】:

          【解决方案5】:

          如果您在项目中使用 maven,那么只需使用这个库:

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

          它是为 Glasfish 服务器创建的,但也适用于 Tomcat(选中)。 有了这个库,您可以轻松地将 JAXB 与 OSGI 包一起使用。

          【讨论】:

            【解决方案6】:

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

            【讨论】:

              【解决方案7】:

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

              【讨论】:

                【解决方案8】:

                我在从事的项目中遇到了类似的问题。看完http://jaxb.java.net/faq/index.html#classloader后发现JAXBContext找不到包含jaxb.in​​dex的包。

                我会尽量说清楚。

                我们有

                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 包限制,那么现在必须非常清楚 Bundle B 不是 Importing package com.cclass CB 类 不可见,因此它无法实例化 C。

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

                希望这对您有所帮助。

                【讨论】:

                  【解决方案9】:

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

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

                  【讨论】:

                  • 当您使用不是为 OSGi 设计的库并对它们获得的类加载器进行假设时,这实际上在 OSGi 环境中通常是一个非常讨厌的问题。这个问题就是为什么人们声称 Eclipselink 是唯一在 OSGi 中工作的 JPA 提供程序(不知道这是否仍然正确)。
                  • 上下文类加载器;设置类加载器时,您应该首先检查是否已经设置了一个,如果是,请将其保留为局部变量,然后在调用 JAX 后在 finally 块中将其重置 - 您不知道还有什么正在使用类加载器黑客。 ..
                  • 是否有与此问题相关的 Jira 项目?我们在这里偶然发现,我可以证明该解决方案有效,我只是想知道这是否是 apache-felix 项目中的一个 awknowledged 问题
                  • @Monachus - 这不是真正的 Felix 问题,更多的是 OSGi 一般 为突然在 OSGi 上下文中使用而没有使用过的库创建了这种类型的问题为它设计的。这确实是设计使然(OSGi 非常注重分离类加载器),因此 OSGi 容器不能,甚至不应该尝试修复。
                  • 谢谢!一点优化: Class c = my.package.name.ObjectFactory.class;类加载器 cl = c.getClassLoader(); JAXBContext jc = JAXBContext.newInstance(c.getPackage().getName(), cl);所以你不会有重命名包的问题。
                  【解决方案10】:

                  编辑 2:

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

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

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

                  【讨论】:

                  • 嗯,它可能(我不知道),但在我看来,应该有一些地方可以放置文件,以便使用的类加载器找到它。
                  猜你喜欢
                  • 1970-01-01
                  • 2016-05-19
                  • 1970-01-01
                  • 1970-01-01
                  • 2019-01-29
                  • 2013-12-30
                  • 2015-06-12
                  • 2014-12-25
                  • 1970-01-01
                  相关资源
                  最近更新 更多