My pom.xml
has this dependency:
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
</dependency>
When I use the XMLSerializer
it throws an exception: java.lang.NoClassDefFoundError: nu/xom/Node
If I run the class locally and add the JAR to my classpath, everything works as expected. I'm running this class as a Jenkins plugin so I don't expect to be manually defining classpath - I figured that's what Maven should be handling.
It's important to note that Jenkins plugins require me uploading an hpi
file that is created from Maven. It is not running based on the output jar
. If I go on Jenkins box and manually put the xom JAR into WEB-INF/libs
, it works. But obviously that means this plugin wouldn't for other people, which is self-defeating.
Here is minimal code causing error: https://github.com/DaveStein/parser-sample
The Readme has exact repro steps.
Note on chosen answer
The PR to my sample repo got me most of the way to where I needed to be. I did have a few other issues that had to get resolved, but the JSONObject conflict was the core problem. I took out all GlobalConfiguration as Jesse's PR suggested. The only other issue that might concern a future viewer was some glitch when using xom
as explicit dependency while also using a higher version than 1.626 for org.jenkins-ci.plugins
at the time of this post.
Jenkins core bundles json-lib
. (A forked copy, not that it matters for purposes of this question.) It does not bundle the optional dependency¹ XOM, whatever that is. When your plugin loads XmlSerializer.class
, it gets defined by the class loader for Jenkins core, which then attempts to link against classes such as nu.xom.Node
. Since this is not available in the defining loader of XmlSerializer
—the Jenkins core class loader (more or less jenkins.war!/WEB-INF/lib/*.jar
)—you get an error. The fact that a class by that name is accessible in your plugin class loader is of no import, excuse the pun.
If your plugin needs to use its own versions of classes which are normally bundled in Jenkins core and exposed to plugins implicitly, then it needs to not only bundle those JARs (a regular compile
-scoped Maven dependency suffices for that purpose), but to also use the pluginFirstClassLoader
option. Before attempting to do so, you had better understand Java class loading semantics thoroughly, or you will be lost in a maze of cryptic² ClassCastException
s and LinkageError
s.
By the way the mvn hpi:run
command normally used to test plugin code iteratively does not simulate a realistic class loading regime. So if you are using pluginFirstClassLoader
or any other tricks in this space, always double-check the resulting class loading behavior by (re-)installing an *.hpi
in a sample Jenkins instance, for example using /pluginManager/advanced
, or the install-plugin
CLI command. Judging by your description, you were already doing that (and perhaps unaware of hpi:run
).
¹The original sin here is use of optional
dependencies. json-lib
should rather have defined a distinct artifact json-lib-xom
with hard dependencies on json-lib
and xom
. That would ensure that any given class loader can either see XmlSerializer
and its dependencies, or neither.
²No progress on JDK-6273389, alas. Marked as a duplicate, but what it is a duplicate of, I am not sure. Theoretically Java 9 modules make questions like this obsolete—by imposing such onerous restrictions that applications like Jenkins could not use that module system to begin with.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With