阿帕奇菲利克斯内运行时,为什么不能JAXB找到我jaxb.in​​dex?(Why can'

2019-06-24 04:02发布

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

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) ),但我看不到发生了什么事情,因为源不在这里。

AND:

从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容器的类加载机制做的。不幸的是,我还是有点在这里我的深度。

Answer 1:

OK,这花了一段挖,但答案并不令人惊奇甚至没有那么复杂:

JAXB找不到jaxb.in​​dex,因为默认情况下, newInstance(String)使用当前线程的类加载器(由返回的Thread.getContextClassLoader() 这并不里面菲利克斯工作,因为OSGi包和框架的线程有独立的类加载器。

解决的办法是从什么地方得到一个合适的类加载器,并使用newInstance(String, ClassLoader) 。 我有一个合适的类加载器中包含包中的类的一个jaxb.index ,灵活性原因明智的选择可能是ObjectFactory

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

也许你也可以得到在该的类加载器Bundle实例使用,但我无法弄清楚如何,以及上述方案似乎还给我。



Answer 2:

我面对我的工作项目类似的问题。 看完后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包的限制,那么它必须很清楚,现在包B未导入包com.cC类没有 B类 可见 ,因此它无法实例C.

该解决方案将是一个ClassLoader传递给bMethod。 这个类加载器应来自被导入com.c捆绑 。 在这种情况下,我们可以通过A.class.getClassLoader(),因为束A被导入com.c

希望这是有益的。



Answer 3:

对于同样的问题,我通过手动把包放入进口解决它。



Answer 4:

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

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

它为Glasfish服务器创建的,但也与Tomcat的工作(检查)。 有了这个库,你可以使用伊斯利与JAXB OSGi包。



Answer 5:

编辑2:

我曾经在我的应用程序也有类似的奇怪的类加载问题。 如果我运行它作为一个正常的应用程序,一切OK了,但是当我调用它作为Windows服务,它开始失败,ClassNotFoundExceptions。 分析表明,该线程有自己的类加载器为空莫名其妙。 我通过对线程设置SystemClassLoader解决了这个问题:

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

不知道,如果你的容器允许这种变化虽然。



Answer 6:

我刚刚碰到这个问题。 对我来说,解决方案是使用IBM的JRE,而不是甲骨文。 好像JAXB实现是在一个更OSGI友好。



Answer 7:

我通过添加含有我生成的类的包成功地解决了这个ObjectFactory<Private-Package>我的束的定义,加的一部分org.jvnet.jaxb2_commons.*



Answer 8:

有可能是另一种情形,可以给这个问题。

当您安装并启动其导出包含jaxb.in​​dex或objectFactory.java包捆绑

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

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

在ServiceMix的(karaf)OSGi容器也面临类似的问题



Answer 9:

对我来说,问题是,这是不相关的,我已经开发的模块单元测试并没有依赖于它的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>


Answer 10:

我的解决办法是:

的JAXBContext上下文= JAXBContext.newInstance( 新类[] { “my.package.name”});

要么

的JAXBContext上下文= 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%



文章来源: Why can't JAXB find my jaxb.index when running inside Apache Felix?