Unrecognized parameter -XsomePlugin error when usi

2019-08-14 21:42发布

问题:

I am compiling an XML Schema using JAXB/XJC and I want to use some XJC plugin to augment generated code.
I include plugin into the XJC classpath and activate it using -XsomePlugin.

However I am getting an error like:

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

So apparently the plugin is not picked up by XJC or is not activated.

What could be the reason and how can I debug this error?

回答1:

XJC discovers and instantiates plugins using a "service loader" mechanism. XJC plugins provide a resource META-INF\services\com.sun.tools.xjc.Plugin which lists FQCN of plugin classes.

There may be different reasons why the plugin could not be loaded/instantiated.

Turning on logging of plugin loading errors

Unfortunately, XJC normally does not show which specific errors occured during instantiation of the plugin. You only get this unrecognized parameter -XsomePlugin message and that's it.

Fortunately, there is a "debug" switch which can be activated using one of the following system properties:

  • com.sun.tools.xjc.Options.findServices=true
  • com.sun.tools.internal.xjc.Options.findServices=true

(I normally set both properties, I'll explain the reason below.)

This would make XJC log the actual error which occured during instantiation of the plugin, for instance:

  [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)
  .....

If you've activated these system properties but still don't see any error message about loading your plugin in the logs, most probable reasons for this are:

  • the plugin library is not correctly added to the XJC classpath;
  • the plugin library is invalid i.e. does not provide the META-INF\services\com.sun.tools.xjc.Plugin resource with FQCNs of the plugin classes.

Internal XJC

There are two flavours of XJC out there:

  • "Standalone" XJC available as the jaxb-xjc-<version>.jar artifact. Used (among others) in maven-jaxb2-plugin.
  • "Internal" XJC packaged with the JDK. This is what is invoked when you call xjc from the command line.

Unfortunately there is a big problem with the "internal" XJC.

When XJC is packaged for the JDK, all XJC packages are renamed from com.sun.tools.xjc.* to com.sun.tools.internal.xjc.*. I guess there are some non-technical reasons behind this but I won't speculate.

When com.sun.tools.xjc.* packages are renamed to com.sun.tools.internal.xjc.*, this essentially breaks compatibility of plugins developed for the "standalone" XJC:

  • An XJC plugin developed for the "standalone" XJC must extend com.sun.tools.xjc.Plugin. "Internal" XJC expects plugin classes to extend com.sun.tools.internal.xjc.Plugin.
  • For the "standalone" XJC plugins must be listed in META-INF\services\com.sun.tools.xjc.Plugin. For the "internal" XJC in META-INF\services\com.sun.tools.internal.xjc.Plugin.

(This is also the reason why you should turn on both com.sun.tools.xjc.Options.findServices=true as well as com.sun.tools.internal.xjc.Options.findServices=true to debug loading of the plugins.)

Basically, plugins developed for the "standalone" XJC are not compatible to the "internal" XJC and vice versa.

To the best of my knowledge, most of the XJC plugins are developed for the "standalone" XJC.

Compatibility of XJC versions 2.3 and pre-2.3

Another problem is that there are incompatible changes between XJC versions.

Thus in XJC 2.3 the class Aspect was moved from the package com.sun.tools.xjc.model to the package com.sun.tools.xjc.outline. This means that plugins which used the com.sun.tools.xjc.model.Aspect in XJC versions earlier than 2.3 won't work with 2.3. There are probably other examples as well.

This means that an XJC plugin may simply be not compatible to the XJC version you use.