当前位置: 首页 > 知识库问答 >
问题:

Eclipse/OSGI、Java11、JAXB和Classloader

闾丘选
2023-03-14

我有两个Java模块,A和B。A提供了一个核心模型,其中包含JAXB注释和帮助器类,用于创建JAXB内容(创建上下文、编组、解组等)。B提供了其他类,这些类通过@xmlanyement(lax=true)包含在模型中,因此必须添加到JAXB上下文中。

这在普通Java-B的classloader中运行良好,它可以看到所有相关的类,并可以使用以下内容实例化JAXB上下文:

JAXBContext.newInstance(RootFromA.class, RootFromB.class)

现在我正在尝试使用OSGI(B是一个Eclipse插件,A是一个核心库,它也将被一个普通Java命令行模块C使用)。经过多次试验和错误,我已经设法让A和B通过OSGI包导入来查看JAXB应用编程接口和实现。问题是,如上所述调用newInstance似乎使用了JAXB API的类加载器,而不是RootFromA的类加载器,当然也不是RootFromB的类加载器。因此,它甚至看不到JAXB实现,并抱怨找不到ContextFactory类。

我已经设法通过调用不同版本的newInstance来解决这个问题:

JAXBContext.newInstance(
  RootFromA.class.getPackageName()
    + ":" + RootFromB.class.getPackageName(),
  RootFromB.class.getClassLoader())

我不喜欢这样,有两个原因:

  1. 我的“客户机”代码(B是A中JAXB助手的客户机)必须手动提供合适的类加载器
  2. 我必须提供jaxb。索引列出上下文类的所有引用包中的文件,即使我的代码完全知道它们,并且实际上从类中获取包名

可能没有办法绕过(1),因为只有B知道完整的类集,并且可以决定谁的类加载器能够看到所有的类。我担心一旦我添加扩展模块C和D,通过Eclipse扩展点连接到B并为JAXB上下文提供额外的类,我可能会遇到更多的麻烦——B的类加载器能够看到这些吗?

但我真的找到了一种方法来摆脱(2)所需的静态索引文件。全套上下文类是动态的,在纯Java中由ServiceLoader决定,在Eclipse中由扩展点决定。在这两种情况下,我都可以直接访问属于上下文的一组完整的类,因此必须考虑手动添加JAXB。将文件索引到每个包是多余的,因此可能是不必要的错误源。

我错过什么了吗?有没有“更好”的方法?为什么没有一个接受一组上下文类和一个类加载器的newInstance方法呢?

共有1个答案

欧阳智志
2023-03-14

看来我找到了解决办法。我的问题是必须出于两个不同的目的处理类加载器:

  1. JAXB用于实例化上下文的类加载器

如上所述,(1)可以在JAXBContext.newInstance()中指定为参数,但仅当将模型指定为包名称而不是单个模型类时。这意味着JAXB必须自己查找类,它唯一可以使用的类加载器是(1)——如果模型类分布在多个包中,它就不能看到所有的模型类。

另一个线程(为什么JAXB在ApacheFelix中运行时找不到我的JAXB.index?)告诉我JAXB默认使用线程上下文类加载器来定位上下文实现。将其设置为可以看到实现的类加载器(例如,我自己的bundle的类加载器)就足以让JAXB找到自己的实现,这让我可以自由地使用类数组调用我的首选版本newInstance()。由于这些类已经加载,JAXB可以按原样使用它们,而不必关心它们的不同类加载器。

简言之:

Class[] myClasses = getModelClasses(); // gather all model classes, which may have different classloaders
Thread thread = Thread.currentThread();
ClassLoader originalClassLoader = thread.getContextClassLoader();
thread.setContextClassLoader(getClass().getClassLoader()); // my own bundle's classloader
JAXBContext context = JAXBContext.newInstance(myClasses);
thread.setContextClassLoader(originalClassLoader); // reset context classloader

上下文类加载器操作可以包装在AutoCloseable中,允许我简单地将JAXBContext实例化包装在一个使用资源尝试的块中。

 类似资料:
  • 我正尝试使用POM优先的方法(生成OSGi元数据)将JAXB模块作为OSGi包加载到Java11和ApacheFelix中。 首先,我尝试了: 但这给了我以下运行时例外: 这可能与以下问题有关,但我不确定:https://github.com/eclipse-ee4j/jaxb-api/issues/78 所以我尝试了v3。0.0但现在我的一个注释处理程序使用JAXB生成XML文档,失败了: 我注

  • 我试图与eclipse部署osgi bundle 如果我出口与eclipse插件(出口- 我的清单: 我的build.properties: 没什么特别的,简单的OSGI捆绑包。eclipse和Jboss - OSGI出了点问题。有没有人知道出了什么问题? Update1: jar的样子:

  • 问题内容: 我开始开发Eclipse插件(从技术上讲,是OSGi插件),遇到的第一个问题是我似乎无法像往常一样控制commons-logging输出。 我在插件依赖项中包含了commons- logging包,的确,当我记录某些信息(信息为INFO或更高严重性)时,它会记录到控制台。但是,我似乎无法以任何较低级别登录(例如DEBUG或TRACE)。 我已经指定了一个log4j.properties

  • 我目前正在尝试用log4j/slf4j和java 11构建一个应用程序,但在运行时我面临这个问题: 此问题的根源代码是我的记录器的初始化: 我依赖于: org.apache.logging.log4j: log4j-api: 2.11.1 org.apache.logging.log4j: log4j-core: 2.11.1 org.apache.logging.log4j: log4j-slf

  • 我使用EclipseIndigo使用OSGiJava框架开发了一些包。有一个主捆绑包,它依赖于其他捆绑包,并且具有要运行的主程序。如果我尝试在Eclipse中运行所有捆绑包,一切都正常工作,但是如果我将每个捆绑包保存为一个JAR,并在命令行中启动OSGi框架,当我尝试启动主捆绑包时,会出现异常<code>NoClassDefFoundError。找不到的类是依赖项。包的其余部分处于活动状态,主包刚

  • 操作系统:Linux Mint 18.3,Eclipse“2019-06”。使用Gradle 5.4的Gradle包装器。 昨天,我花了大约4个小时试图在Eclipse中组合一个项目,当使用Java11时,这个项目实际上会运行并显示一个JavaFX场景。由于这里的帮助,我最终还是做到了。 但这只是Eclipse中一个沼泽标准的“Java项目”。我实际上需要做的是开发一个Gradle项目,使用Gro