首页 > 解决方案 > 使用 JAXB/XJC 插件时出现无法识别的参数 -XsomePlugin 错误

问题描述

我正在使用 JAXB/XJC 编译 XML 模式,并且我想使用一些 XJC 插件来增强生成的代码。
我将插件包含到 XJC 类路径中并使用-XsomePlugin.

但是我收到如下错误:

Caused by: com.sun.tools.xjc.BadCommandLineException: unrecognized parameter -XsomePlugin
    at com.sun.tools.xjc.Options.parseArguments(Options.java:859)
    at com.sun.tools.xjc.XJCBase._doXJC(XJCBase.java:804)
    ... 21 more

所以显然该插件没有被 XJC 拾取或未被激活。

可能是什么原因,我该如何调试这个错误?

标签: javajaxbxjcmaven-jaxb2-plugin

解决方案


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工件提供。中使用(除其他外)。
  • 与 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.

(这也是您应该同时打开com.sun.tools.xjc.Options.findServices=truecom.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。这意味着com.sun.tools.xjc.model.Aspect在 2.3 之前的 XJC 版本中使用的插件将不适用于 2.3。可能还有其他例子。

这意味着 XJC 插件可能与您使用的 XJC 版本不兼容。


推荐阅读