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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1043109/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 22:37:28  来源:igfitidea点击:

Why can't JAXB find my jaxb.index when running inside Apache Felix?

javajaxbosgiapache-felix

提问by Hanno Fietz

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

我得到一个 JAXBException 说

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

“my.package.name”不包含 ObjectFactory.class 或 jaxb.in​​dex

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.

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

ETA:

预计到达时间

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

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

From my previousexperience, 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.

根据我之前的经验,我猜测这与运行它的 OSGi 容器的类加载机制有关。不幸的是,我在这里仍然有点超出我的深度。

采纳答案by Hanno Fietz

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.

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

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:

解决方案是从某处获取合适的类加载器并使用newInstance(String, ClassLoader). 我从包含的包中的一个类中获得了一个合适的类加载器,jaxb.index出于灵活性原因,一个明智的选择可能是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 Bundleinstance is using, but I couldn't figure out how, and the above solution seems safe to me.

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

回答by akarnokd

Edit 2:

编辑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:

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

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

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

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

回答by Chaits

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

我正在处理的项目中遇到了类似的问题。阅读http://jaxb.java.net/faq/index.html#classloader 后,我意识到 JAXBContext 无法找到包含 jaxb.in​​dex 的包。

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

JAXB 相关B 类是 JAXBContext,bMethod 是 newInstance()

If you are familiar with OSGi package restrictions then it must be very clear now that Bundle Bis not Importing package com.ci.e class Cis not visibleto class Bhence it cannot instantiate C.

如果您熟悉的OSGi包的限制则必须十分现在很清楚,捆B未导入包com.cC类不可见的B类,因此它无法实例C.

The solution would be to pass a ClassLoaderto 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

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

Hope this was helpful.

希望这是有帮助的。

回答by Zoltan

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.

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

回答by Hart

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

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

回答by wierzbiks

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

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

<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.

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

回答by vikingsteve

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

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

回答by Peter

My Solution was:

我的解决方案是:

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

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

OR

或者

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

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%

工作 100%

回答by Naveen Raj

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

当您安装并启动导出包含 jaxb.in​​dex 或 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

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

Faced similar issue in servicemix(karaf) osgi container

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

回答by Amit Biton

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.

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

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

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

added the following dependency:

添加了以下依赖项:

<dependency>
    <groupId>com.myCompany</groupId>
    <artifactId>my-module-name</artifactId>
    <version>${project.version}</version>
    <scope>test</scope>
</dependency>