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?
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.