JAXB + OSGi 与 Java 11

问题描述

我正在尝试使用 POM 优先方法生成 Osgi 元数据)将 JAXB 模块作为 Osgi 包与 Java 11 和 Apache Felix 一起加载。

首先我尝试了:

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

但这给了我以下运行时异常:

SCHWERWIEGEND: Implementation of JAXB-API has not been found on module path or classpath.  
javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath.
 - with linked exception: 
[java.lang.classNotFoundException: com.sun.xml.bind.v2.ContextFactory]

它可能与以下问题有关,但我不确定:https://github.com/eclipse-ee4j/jaxb-api/issues/78

所以我尝试使用 v3.0.0,但现在我的一个使用 JAXB 生成 XML 文档的注释处理器失败了:

Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project my-module: Compilation failure
Implementation of JAXB-API has not been found on module path or classpath.

我注意到 jaxb-osgi-3.0.0.jar 不再提供 com.sun.xml.bind

我也尝试从 javax.xml.bind 迁移到 jakarta.xml.bind,但是从 XSD 生成 POJO 类的 Maven 插件在撰写本文时似乎还没有准备好({{ 1}} 或 org.jvnet.jaxb2.maven2:maven-jaxb2-plugin)。

我的问题:

  1. 我可以从哪里获得 org.codehaus.mojo:jaxb2-maven-plugin
  2. com.sun.xml.bindjaxb-osgi 模块有何关联?
  3. 这一切应该如何运作?
  4. 我该如何继续?

更新 - 背景信息

我有以下基于 Extender Pattern 的设置:

  • 核心扩展模块M:
    • 提供一些 JAXB 类
    • 一个 BundleTracker,用于从一些包 X、Y、Z 的 meta-inf 子目录解组 XML 文档
    • 用于编组 XML 文档的抽象自定义注释处理器
  • 扩展模块 A、B、C:
    • 提供额外的 JAXB 类(从 XSD 生成
    • 使用声明式服务注册扩展
    • 自定义注释
    • 注释处理器将注释属性转换为基于 JAXB 的模型并在预期位置生成 XML 文档
  • 扩展模块 X、Y、Z
    • 使用模块 A、B、C 的注解
    • 使用 A、B、C 的注解处理器生成 XML 文档

目标:应该很容易创建扩展模块,例如 X、Y、Z

Java SE 8 一切正常,其中 JAXB 仍与 JRE 捆绑在一起。

更新 1

因为 Maven 插件还没有准备好,我现在只能使用 v2.3.3。

我更改了以下内容

解决jaxb-impl 问题(尽管这似乎不是正确的解决方案),但现在虽然生成了 ObjectFactory,但无法找到它们。

更新 2

我现在使用的是经过修改java.lang.classNotFoundException: com.sun.xml.bind.v2.ContextFactory 包(参见 issue)和 Apache Aries SPI Fly Dynamic Weaving Bundle (1.3.2)(参考实现Osgi ServiceLoader Mediator 规范),我在核心模块 M 中添加了以下要求:

jaxb-osgi

服务似乎被检测到:

Require-Capability: [...],osgi.extender;filter:="(o
 sgi.extender=osgi.serviceloader.processor)",osgi.serviceloader;filter:=
 "(osgi.serviceloader=javax.xml.bind.JAXBContextFactory)";cardinality:=m
 ultiple,[...]"

但我仍然得到:

2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.xml.bind.v2.JAXBContextFactory of service javax.xml.bind.JAXBContextFactory in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.code_injector.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.locator.sourceLocationAddOn of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.sync.SynchronizedMethodAddOn of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.at_generated.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.episode.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi
2021-02-13 12:09:31 INFO org.apache.aries.spifly.BaseActivator log - Registered provider com.sun.tools.xjc.addon.accessors.PluginImpl of service com.sun.tools.xjc.Plugin in bundle com.sun.xml.bind.jaxb-osgi

为什么它会尝试通过 ServiceLoader 加载硬编码的javax.xml.bind.JAXBException: Implementation of JAXB-API has not been found on module path or classpath. - with linked exception: [java.lang.classNotFoundException: com.sun.xml.bind.v2.ContextFactory not found by 而不是 com.sun.xml.bind.v2.ContextFactory

解决方法

在 OSGI 环境中使用 JAXB 时,您需要注意几个问题:

  1. 您需要将包 jaxb-osgi jakarta.xml.bind-api 添加到您的 OSGI 容器中,
  2. com.sun.xml.bind.v2;version="[2.3,3)" 添加到包的 Import-Package 标头中,
  3. JAXBContext 将无法扫描其他包以寻找 JAXB 的实现,因此您需要将 jaxb.properties 添加到包含具有内容的模型的包中:
javax.xml.bind.context.factory=com.sun.xml.bind.v2.JAXBContextFactory
  1. 如果您调用 JAXBContext.newInstance(Class) 工厂方法,请确保将 ContextClassLoader 设置为您的包的 ClassLoader
,

由于每个 OSGI 包都使用自己的类加载器,因此 JAXB API 无法使用标准 ServiceLoader 来定位 JAXB 实现。但是,从 2.2.2 版开始,JAXB API 可以使用 osgi-resource-locator 作为后备。

因此,为了在 Java 11 上使用 JAXB,您只需要:

  1. 添加对 javax.xml.bindorg.glassfish.hk2.osgiresourcelocator 包的依赖,
  2. osgi-resource-locatorjaxb-osgi 包与您的包一起部署。

备注:如果您想使用 MOXy,则需要额外的步骤,因为 MOXy 不附带 META-INF/services/javax.xml.bind.JAXBContext 文件(参见 this answer)。