Reputation: 1126
I'm trying to make a Jenkins plugin that uses a library that requires spring-core 3.2.2 (cloudfoundry-client-lib). I simply used the mvn command to create a skeleton plugin, then added my Maven dependency to pom.xml and a few simple code lines that uses the library. I'm not getting any problem running the skeleton plugin without my dependency.
Upon compiling with "mvn package", I'm getting a test error:
WARNING: Failed to scout hudson.security.PAMSecurityRealm
java.lang.InstantiationException: java.lang.NoClassDefFoundError: org/springframework/core/env/EnvironmentCapable
Looks like this is a class that appeared in spring-core 3.1.0. So I looked at the Maven dependency tree:
[INFO] --- maven-dependency-plugin:2.3:tree (default-cli) @ stackato-jenkins ---
[INFO] org.wiwiweb:cf-test-jenkins:hpi:1.0-SNAPSHOT
[INFO] \- org.cloudfoundry:cloudfoundry-client-lib:jar:1.0.2:compile
[INFO] \- org.springframework:spring-webmvc:jar:3.2.2.RELEASE:compile
[INFO] \- org.springframework:spring-core:jar:2.5.6.SEC03:compile
So Maven tells me it's using spring-core 2.5.6 because of spring-webmvc 3.2.2? This is strange because, looking online, spring-webmvc 3.2.2 depends on spring-core 3.2.2. Looking at the verbose version of the tree, looks like jenkins-core depends on spring-core 2.5.6... This makes me suspicious that the problem is from Jenkins.
Anyway, if it's just a version conflict, then overriding Maven's decision by explicitly saying I want spring-core 3.2.2 in my pom.xml should solve the problem, right? I did this, then did not get a compile error. Problem solved!... not.
In runtime, after activating this plugin in Jenkins and running a build with this, as soon as the code runs into a line that uses the library I added, the Jenkins output tells me this:
FATAL: org.springframework.util.CollectionUtils.unmodifiableMultiValueMap(Lorg/springframework/util/MultiValueMap;)Lorg/springframework/util/MultiValueMap;
java.lang.NoSuchMethodError: org.springframework.util.CollectionUtils.unmodifiableMultiValueMap(Lorg/springframework/util/MultiValueMap;)Lorg/springframework/util/MultiValueMap;
UnmodifiableMultiValueMap() is a method that was added in spring-core 3.1, so this means Jenkins is still trying to run my plugin with the old version of spring-core, even though I explicitly said I wanted the newest one in my plugin's pom.xml!
So I'm stuck on this. I'm not even sure if it's a Maven or a Jenkins issue. I'll sum up the whole thing in two questions:
Upvotes: 3
Views: 2330
Reputation: 5593
If you're picking up dependencies from the Jenkins install rather than from your plugin the solution is actual quite easy to implement. Per the Jenkins documentation, simply add the maven-hpi-plugin to the build in the pom.xml of your Jenkins plugin and set it to load the plugin classes first:
<build>
<plugins>
<plugin>
<groupId>org.jenkins-ci.tools</groupId>
<artifactId>maven-hpi-plugin</artifactId>
<configuration>
<pluginFirstClassLoader>true</pluginFirstClassLoader>
</configuration>
</plugin>
</plugins>
</build>
Upvotes: 2
Reputation: 52368
Try to "shade" the CF client lib using the Maven Shade plugin, as it seems Jenkins doesn't like plugins that are using a different version of Spring than the one it uses internally itself.
Even if your own plugin doesn't use Spring directly, but the CF library does, I believe this still applies. The person that suggested shading in the jenkinsci-dev mailing list seems to be involved in Jenkins plugins development, so he might know about this more than others.
These being said, I would get the source code for cf-client-lib, I would change the pom.xml
to consider shading for org.springframework
package, as well (because cf-client-lib already uses shading for org.codehaus.jackson
package) and I would use this "shaded" version of cf-client-lib in the Jenkins plugin.
Upvotes: 2