XJC 使用“服务加载器”机制发现和实例化插件。 XJC 插件提供了一个资源META-INF\services\com.sun.tools.xjc.Plugin,其中列出了插件类的 FQCN。
插件无法加载/实例化可能有多种原因。
开启插件加载错误日志
不幸的是,XJC 通常不会显示在插件实例化期间发生了哪些特定错误。您只会收到此unrecognized parameter -XsomePlugin 消息,仅此而已。
幸运的是,有一个“调试”开关可以使用以下系统属性之一激活:
com.sun.tools.xjc.Options.findServices=true
com.sun.tools.internal.xjc.Options.findServices=true
(我一般两个属性都设置了,下面我会解释原因。)
这将使 XJC 记录插件实例化过程中发生的实际错误,例如:
[xjc] java.util.ServiceConfigurationError: com.sun.tools.xjc.Plugin: Provider org.jvnet.jaxb2_commons.plugin.tostring.ToStringPlugin could not be instantiated
[xjc] at java.base/java.util.ServiceLoader.fail(ServiceLoader.java:581)
[xjc] at java.base/java.util.ServiceLoader.access$100(ServiceLoader.java:390)
[xjc] at java.base/java.util.ServiceLoader$ProviderImpl.newInstance(ServiceLoader.java:799)
[xjc] at java.base/java.util.ServiceLoader$ProviderImpl.get(ServiceLoader.java:721)
[xjc] at java.base/java.util.ServiceLoader$3.next(ServiceLoader.java:1389)
[xjc] at com.sun.tools.xjc.Options.findServices(Options.java:1009)
[xjc] at com.sun.tools.xjc.Options.getAllPlugins(Options.java:385)
[xjc] at com.sun.tools.xjc.Options.parseArgument(Options.java:724)
[xjc] at com.sun.tools.xjc.Options.parseArguments(Options.java:857)
....
[xjc] Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "org.slf4j.impl.StaticLoggerBinder.getLoggerFactory()Lorg/slf4j/ILoggerFactory;" the class loader (instance of org/apache/tools/ant/AntClassLoader) of the current class, org/slf4j/LoggerFactory, and the class loader (instance of org/apache/tools/ant/loader/AntClassLoader5) for the method's defining class, org/slf4j/impl/StaticLoggerBinder, have different Class objects for the type org/slf4j/ILoggerFactory used in the signature
[xjc] at org.slf4j.LoggerFactory.getILoggerFactory(LoggerFactory.java:306)
[xjc] at org.slf4j.LoggerFactory.getLogger(LoggerFactory.java:276)
[xjc] at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:156)
[xjc] at org.apache.commons.logging.impl.SLF4JLogFactory.getInstance(SLF4JLogFactory.java:132)
[xjc] at org.apache.commons.logging.LogFactory.getLog(LogFactory.java:274)
[xjc] at org.jvnet.jaxb2_commons.plugin.AbstractPlugin.<init>(AbstractPlugin.java:28)
.....
如果您已激活这些系统属性,但在日志中仍未看到有关加载插件的任何错误消息,最可能的原因是:
- 插件库未正确添加到 XJC 类路径中;
- 插件库无效,即没有为
META-INF\services\com.sun.tools.xjc.Plugin 资源提供插件类的 FQCN。
内部 XJC
XJC 有两种口味:
- “独立”XJC 作为
jaxb-xjc-<version>.jar 工件提供。在maven-jaxb2-plugin 中使用(以及其他)。
- 与 JDK 一起打包的“内部”XJC。这是当您从命令行调用
xjc 时调用的内容。
不幸的是,“内部”XJC 有一个大问题。
当为 JDK 打包 XJC 时,所有 XJC 包都从 com.sun.tools.xjc.* 重命名为 com.sun.tools.internal.xjc.*。我想这背后有一些非技术原因,但我不会推测。
当 com.sun.tools.xjc.* 包被重命名为 com.sun.tools.internal.xjc.* 时,这从根本上破坏了为“独立”XJC 开发的插件的兼容性:
- 为“独立”XJC 开发的 XJC 插件必须扩展
com.sun.tools.xjc.Plugin。 “内部”XJC 期望插件类扩展 com.sun.tools.internal.xjc.Plugin。
- 对于“独立”的 XJC 插件,必须在
META-INF\services\com.sun.tools.xjc.Plugin 中列出。对于META-INF\services\com.sun.tools.internal.xjc.Plugin中的“内部”XJC。
(这也是您应该同时打开com.sun.tools.xjc.Options.findServices=true 和com.sun.tools.internal.xjc.Options.findServices=true 来调试插件加载的原因。)
基本上,为“独立”XJC 开发的插件与“内部”XJC 不兼容,反之亦然。
据我所知,大多数 XJC 插件都是为“独立”XJC 开发的。
XJC 2.3 和 pre-2.3 的兼容性
另一个问题是XJC版本之间存在不兼容的变化。
因此,在 XJC 2.3 中,类 Aspect 从包 com.sun.tools.xjc.model 移动到包 com.sun.tools.xjc.outline。这意味着在 2.3 之前的 XJC 版本中使用 com.sun.tools.xjc.model.Aspect 的插件将不适用于 2.3。可能还有其他例子。
这意味着 XJC 插件可能与您使用的 XJC 版本不兼容。