问题描述
我正在尝试使用 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
)。
我的问题:
- 我可以从哪里获得
org.codehaus.mojo:jaxb2-maven-plugin
? -
com.sun.xml.bind
和jaxb-osgi
模块有何关联? - 这一切应该如何运作?
- 我该如何继续?
更新 - 背景信息
我有以下基于 Extender Pattern 的设置:
- 核心扩展模块M:
- 扩展模块 A、B、C:
- 扩展模块 X、Y、Z
- 使用模块 A、B、C 的注解
- 使用 A、B、C 的注解处理器生成 XML 文档
目标:应该很容易创建扩展模块,例如 X、Y、Z
Java SE 8 一切正常,其中 JAXB 仍与 JRE 捆绑在一起。
更新 1
因为 Maven 插件还没有准备好,我现在只能使用 v2.3.3。
我更改了以下内容:
-
我在几个模块的 maven-bundle-plugin 中添加了以下配置:
com.sun.xml.bind.v2,*
这解决了 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 时,您需要注意几个问题:
- 您需要将包 jaxb-osgi 和 jakarta.xml.bind-api 添加到您的 OSGI 容器中,
- 将
com.sun.xml.bind.v2;version="[2.3,3)"
添加到包的Import-Package
标头中, -
JAXBContext
将无法扫描其他包以寻找 JAXB 的实现,因此您需要将jaxb.properties
添加到包含具有内容的模型的包中:
javax.xml.bind.context.factory=com.sun.xml.bind.v2.JAXBContextFactory
- 如果您调用
JAXBContext.newInstance(Class)
工厂方法,请确保将ContextClassLoader
设置为您的包的ClassLoader
。
由于每个 OSGI 包都使用自己的类加载器,因此 JAXB API 无法使用标准 ServiceLoader
来定位 JAXB 实现。但是,从 2.2.2 版开始,JAXB API 可以使用 osgi-resource-locator 作为后备。
因此,为了在 Java 11 上使用 JAXB,您只需要:
- 添加对
javax.xml.bind
和org.glassfish.hk2.osgiresourcelocator
包的依赖, - 将
osgi-resource-locator
和jaxb-osgi
包与您的包一起部署。
备注:如果您想使用 MOXy,则需要额外的步骤,因为 MOXy 不附带 META-INF/services/javax.xml.bind.JAXBContext
文件(参见 this answer)。