为什么 JAXB 在 Apache Felix 中运行时找不到我的 jaxb.in​​dex?

发布于 2024-07-25 06:07:35 字数 2012 浏览 3 评论 0原文

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

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的源代码来看,我发现这里,这可能是一段无法按预期工作的代码:

/**
 * 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 容器的类加载机制。不幸的是,我在这里仍然有点超出我的深度。

It's right there, in the package that it should be indexing. Still, when I call

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

I get a JAXBException saying that

"my.package.name" doesnt contain ObjectFactory.class or jaxb.index

although it does contain both.

What does work, but isn't quite what I want, is

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

This question from various other people appears on quite some mailing lists and forums but seemingly doesn't get answers.

I'm running this on OpenJDK 6, so I got the source packages and stepped my debugger into the library. It starts by looking for jaxb.properties, then looks for system properties and failing to find either, it tries to create the default context using com.sun.internal.xml.bind.v2.ContextFactory. In there, the Exception gets thrown (inside ContextFactor.createContext(String ClassLoader, Map)), but I can't see what's going on because the source isn't here.

ETA:

Judging from the source code for ContentFactory, I found here, this is probably the piece of code that fails to work as intended:

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

From my previous experience, I'm guessing that this has to do with the class loading mechanisms of the OSGi container that this is running in. Unfortunately, I am still a little out of my depth here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

南薇 2024-08-01 06:07:35

好的,这需要相当多的挖掘,但答案并不那么令人惊讶,甚至没有那么复杂:

JAXB 找不到 jaxb.in​​dex,因为默认情况下,newInstance(String) 使用当前线程的类加载器(由 Thread.getContextClassLoader() 返回)。 这在 Felix 中不起作用,因为 OSGi 包和框架的线程具有单独的类加载器。

解决方案是从某处获取合适的类加载器并使用 newInstance(String, ClassLoader)。 我从包含 jaxb.in​​dex 的包中的一个类中获得了一个合适的类加载器,出于灵活性原因,一个明智的选择可能是 ObjectFactory

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

也许您也可以访问Bundle 实例正在使用的类加载器,但我不知道如何实现,并且上述解决方案对我来说似乎是安全的。

OK, this took quite some digging, but the answer is not that surprising and not even that complicated:

JAXB can't find jaxb.index, because by default, newInstance(String) uses the current thread's class loader (as returned by Thread.getContextClassLoader()). This doesn't work inside Felix, because the OSGi bundles and the framework's threads have separate class loaders.

The solution is to get a suitable class loader from somewhere and use newInstance(String, ClassLoader). I got a suitable class loader from one of the classes in the package that contains jaxb.index, a sensible choice for flexibility reasons probably is ObjectFactory:

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

Maybe you could also get at the class loader that the Bundle instance is using, but I couldn't figure out how, and the above solution seems safe to me.

痴情 2024-08-01 06:07:35

我正在从事的项目遇到了类似的问题。 阅读 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 不导入包 com .c类C对于类B不可见,因此它无法实例化C。

解决方案是传递<类加载器到bMethod。 该类加载器应该来自导入 com.c 的包。 在这种情况下,我们可以传递 A.class.getClassLoader() 因为 bundle A 正在导入 com.c

希望这会有所帮助。

I faced similar issue with the project I am working on. After reading http://jaxb.java.net/faq/index.html#classloader I realized that JAXBContext is not able to find the package containing jaxb.index.

I will try to make this as clear as possible.

We have

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

To relate to JAXB. class B is JAXBContext and bMethod is newInstance()

If you are familiar with OSGi package restrictions then it must be very clear now that Bundle B is not Importing package com.c i.e class C is not visible to class B hence it cannot instantiate C.

The solution would be to pass a ClassLoader to bMethod. This ClassLoader should come from a bundle that is importing com.c. In this case we can pass A.class.getClassLoader() since bundle A is importing com.c

Hope this was helpful.

时光磨忆 2024-08-01 06:07:35

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

For the same problem, I resolved it by manually putting the package into the import.

别再吹冷风 2024-08-01 06:07:35

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

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

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

If you are using maven in your project, then just use this library:

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

It's created for Glasfish server but also working with Tomcat (checked).
With this library you can easly use JAXB with OSGI bundles.

爱冒险 2024-08-01 06:07:35

编辑2:

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

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

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

Edit 2:

I once had similar strange class loading problem in my application. If I run it as a normal application, everything was OK but when I invoked it as a Windows Service, it started to fail with ClassNotFoundExceptions. The analysis showed that the threads have their classloaders as null somehow. I solved the problem by setting the SystemClassLoader on the threads:

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

Don't know if your container allows this kind of change though.

千紇 2024-08-01 06:07:35

我刚刚遇到这个问题。 对我来说,解决方案是使用 IBM 的 JRE 而不是 Oracle 的。 看起来 JAXB 实现在该实现中对 OSGI 更加友好。

I've just run into this issue. For me, the solution was to use IBM's JRE instead of Oracle's. Seems like the JAXB implementation is more OSGI-friendly in that one.

向地狱狂奔 2024-08-01 06:07:35

我通过将生成的包含 ObjectFactory 的类的包添加到捆绑包定义的 部分以及 org.jvnet,成功解决了此问题。 jaxb2_commons.*

I successfully resolved this by adding the package of my generated classes containing ObjectFactory to the <Private-Package> part of my bundle definition, plus org.jvnet.jaxb2_commons.*

剑心龙吟 2024-08-01 06:07:35

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

当您安装并启动导出包含 jaxb.in​​dex 或 objectFactory.java 的包的包时

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

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

在 servicemix(karaf) osgi 容器中面临类似的问题

There may be another scenario which can give this problem.

When you install and start a bundle which export the package that contains the jaxb.index or objectFactory.java

Then please make sure that the bundles importing the classes are stopped or pointing to the correct package name.

Also check the export and import statements in the pom.xml

Faced similar issue in servicemix(karaf) osgi container

听,心雨的声音 2024-08-01 06:07:35

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

For me the problem was that a unit test which was not related to the module that I have developed did not had a dependency in it pom.xml to my module.
The UT still recognized my module due to fetching the packages list from shared configuration file.

When running the UT it didn't compile the new module so it didn't generate the ObjectFactory.java therefore I received the error even though when I compiled the module I was able to see the ObjectFactory.java

added the following dependency:

<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>
素染倾城色 2024-08-01 06:07:35

我的解决方案是:

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

或者

JAXBContext context = 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% 有效

My Solution was:

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

OR

JAXBContext context = JAXBContext.newInstance(new Class[]{class.getName()});

OR

a full solution:

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

Works 100%

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文