Spring-core dependency version error with a Jenkins Plugin - spring

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:
Why is Maven not compiling the plugin with a correct version of spring-core unless I explicitly tell him to? It should be able to follow dependencies without me giving it hints.
Why is Jenkins running my plugin with an older version of spring-core than the one it was compiled with, and how can I make it use the correct one?

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>

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.

Related

maven-release-plugin - Not found

I am trying to add maven release plugin to pom.xml file but it returns
Plugin 'org.apache.maven.plugins:maven-release-plugin:' not found
What you're seeing is your IDE complaining that it doesn't know (yet) about this new plugin you've added. It looks like Intellij IDEA from Jetbrains, so my first advice would be to:
run a maven goal that includes this plugin; for example mvn release:help. This will make sure the plugin gets resolved and downloaded (it is in central so should give no problems)
you should also see the release plugin be listed in the maven tab in IDEA now under plugins
tell IDEA to update it's own state from maven. IDEA has a hard time detecting new plugins, as they're not part of the normal project build dependencies. See Force Intellij IDEA to reread all maven dependencies
If the maven goal runs fine, the plugin is working. Try refreshing in IDEA or closing + reopening the project a few times until IDEA gets it.
Regarding the "missing" version tag. If you're not specifing an exact version of the plugin to use, you're currently getting this plugin (version) from the maven super pom:
https://maven.apache.org/ref/3.8.5/maven-model-builder/super-pom.html
you can run the following maven command to view your combined effective pom; super pom, your own pom + default bindings: mvn help:effective-pom
your current configuration should be sufficient, but if you want more control you can specify a version explicitly. See the following link for available version: https://search.maven.org/artifact/org.apache.maven.plugins/maven-release-plugin
if you really want this "error" from IDEA to go away, you must specify the version. It seems IDEA doesn't understand that the version is inherited from the super pom. You can tell because the error message org.apache.maven.plugins:maven-release-plugin: is in the format of groupid:artifactid:version, and version is missing. Adding a version would look like something like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
</plugin>
(this is the default for maven 3.8.5, you can pick a newer version if you want)

How to read this google components dependencies in this pom?

I am looking at jar hell right now between selenium and a google cloud jar. selenium is a bit out of date but in trying to see the versions in the pom file found here, I see no versions...
https://repo1.maven.org/maven2/com/google/auth/google-auth-library-oauth2-http/0.17.1/
How to tell what the version of guava that it will use is?
I saw something like this but not sure how to run it
mvn -P help:effective-pom -Dverbose
I use gradle so not sure how to point that at the remote artifact. I can use gradle to see what version it's bringing in, but what I don't get is how there is no version in the pom file and where gradle is getting it from. I am praying it's not just bringing in the latest version as that would be really really bad and create an unreproducible build over time where if we tag a version of our release, later when we build, it would bring in the wrong jars and could break. Where is the version coming from for guava there?
thanks,
Dean
The POM defines a parent POM, which is
https://repo1.maven.org/maven2/com/google/auth/google-auth-library-parent/0.17.1/google-auth-library-parent-0.17.1.pom
Here you find the version of guava as a property, which is then used in the <dependencyManagement>.

Sonar Maven plugin is failing because of a newer maven assembler plugin, how can I get the new plugin to pass properties correctly?

Had to update our maven assembler version to 1.1.8 from 1.1.6. It's the only change that happened and now Sonar Maven Plugin is throwing this exception:
[ERROR] Failed to execute goal org.sonarsource.scanner.maven:sonar-maven-plugin:3.0.2:sonar
(default) on project ReconCoverage: java.util.ArrayList cannot be cast to java.lang.String ->
Plugins:
<groupId>org.codehaus.mojo</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>2.7</version>
<groupId>com.CORPNAME.raptor.build</groupId>
<artifactId>assembler-maven-plugin</artifactId>
<version>1.1.8</version>
I have been looking into this for about a week, upgrading to this assembler version is required. No other teams are experiencing this issue from the upgrade because they are using Sonar through jenkins. I'm using the maven plugin because our project has many modules, and it structures the coverage results to match it.
I have looked through sonar's code and it seems to be happening in sonar.batch.bootstrap.userproperties. I'm guessing this is happening when the sonar properties are being passed in, items like: sonar.language, sonar.java.coveragePlugin, sonar.host.url, etc. etc.
Example of Coverage Properties:
<sonar.language>java</sonar.language>
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
<sonar.host.url>http://corp.sonar.url/</sonar.host.url>
<sonar.jdbc.url>jdbc:oracle:thin:#sonardb.corp.com:0000:sonardb</sonar.jdbc.url>
<sonar.jdbc.username>username</sonar.jdbc.username>
<sonar.jdbc.password>password</sonar.jdbc.password>
<sonar.jdbc.driver>oracle.jdbc.driver.OracelDriver</sonar.jdbc.driver>
According to sonar's code, it normally takes properties through a Map. And it throws this exception when one of those strings is an array list. Is there anyway to configure my properties so that the new maven assembler will pass these values correctly?
We have implemented a workaround in version 3.1.1 to circumvent buggy plugins injecting non string properties:
https://jira.sonarsource.com/browse/MSONAR-145
To use it just update you pom.xml to use:
<groupId>org.sonarsource.scanner.maven</groupId>
<artifactId>sonar-maven-plugin</artifactId>
<version>3.1.1</version>
I finally found a workaround for this problem. I decided to not go the route of running Java 7 and then 8 to build the coverage report(check previous answers and comments). I'm sure that would work, but since none of our dev or CI machines had Java 8 environments set up, I tried a different route.
I was initially building the sonar report at the end of a mvn clean install through a module CoverageModule(which as the last module to build). The 1.1.8 java assembler version was throwing a fit when it built the project, and then ran the analysis.
I kept the module so that during a normal build, it would still run my ant task plugin to merge all of our module's Jacoco reports. I removed the sonar-maven-plugin from that module's pom and put it in the Project's aggregator module(parent of all modules). After running a full mvn clean install, I can run a mvn sonar:sonar and there appears to be no conflict with the new assembler version, and the old sonar version I was using.

Maven3 - How do I found dependency resolution? ( mvn depedency:tree does not work for mvn3 )

With maven-3, it uses aether to resolve dependency.
Unfortunately, "mvn dependency:tree" use legacy (maven-2) resolution engine.
How do I find out the true dependency resolution for maven-3. I'm running into an issue where "exec:exec" creates different classpath then "dependency:tree".
In maven 3 - compatibility notes, it says I need to use "-X" and look at the log but there is no pointer what to look for.
Also, "assembly:assembly" brings in different 'jar' than when I print out classpath from "exec:exec".
dependency:tree is the correct way to get the project dependencies. Since version 2.5 of the plugin it now resolves the tree using aether.
exec:exec runs the maven exec plugin. The classpath it generates is based on the plugin dependencies, if specified. It is relevant only for the purpose of the plugin execution and not to be taken in the context of project.
The similar explanation holds good in case of assembly:assembly. The jars that it brings in entirely depends on the plugin and assembly-descriptor configuration.
Since version 2.5 of the Maven Dependency Plugin, dependency:tree works with Maven 3 (see the bug report, and the release notes)

How to release Maven multi-module project with inter-project dependencies?

Lets say we have 3 layers project. DB, Business, Web and aggregating pom.
Project
|-DB
| |-pom.xml
|-Business
| |-pom.xml
|-pom.xml
All modules are ment to be released and branched together, so Aggregator pom is configured to assign the same version to all submodules. We have the following versions:
DB-0.1-SNAPSHOT
Business-0.1-SNAPSHOT which depends on DB-0.1-SNAPSHOT
Web-0.1-SNAPSHOT which depends on Business-0.1-SNAPSHOT
When doing release:prepare, all versions updated to 0.1, but prepare fails because there is no DB-0.1 in dependency yet.
One solution is to create different projects for every module and release them one by one while using versions:use-releases plugin to update dependency to 0.1
But I do not like this idea because it requires a lot of configuration and scripting. So, I prefer to use aggregation and release all modules with single command, but the problem is, as I wrote above, when release plugin tries to build Business-0.1 there is no DB-0.1 in repository yet.
Is there any way to manage these inter-project dependencies?
Thanks.
UPD:
even install goal fails.
DB Build - OK (no snapshot nor release version is in any repository)
Business - Failure (DB-0.1-SNAPSHOT not found in repository. But it's even not supposed to be there yet!)
I'm using maven 3.0.2 and release plugin 2.1
your project should define the version only in the parent (project) only once. And let all other modules have a parent relationship. This means you don't have a aggregation. You have a multimodule build instead.
Project
|-pom.xml (version 0.1-SNAPSHOT)
|-DB
| |-pom.xml (parent: ..)
|-Business
| |-pom.xml (parent:..)
This will solve your problem (May be you can take a look here as an example).
I was able to succeed at doing this using Maven 3.3.9...but let me describe my case scenario:
I work with a Java framework called Liferay, where there is a tool called Service Builder that can build and deploy services using Maven with the exact structure as you described:
Service Layer
|-pom.xml (version 1.12.0-SNAPSHOT)
|-Service Portlet
| |-pom.xml (version 1.16.0-SNAPSHOT)<---
|-Service | Artifact dependency
| |-pom.xml (version 1.5.0-SNAPSHOT)-----
As you can see, the portlet app module is built with the service being a dependency, which is a .jar file that packs interfaces among other things for the services to work.
By the way, I did this with my project using modules of different versions. I found an interesting article talking about this practice: Releasing modules of a multi-module project with independent version numbers. You can read the abstract to draw your own conclusions about if versioning modules is appropriate or not... but from my point of view, after reading the demands of the Client, it seems reasonable to me that versioning of modules should be a feature supported by Maven without being too painful to implement.
Running mvn release:prepare and mvn:perform inside the parent (Service Layer) was the way to go. Maven makes the release building and deployment in the following order: 1) parent pom 2) service dependency 3) service portlet.
Maven took care of the order, and that is nice...but the service dependency is built based on the portlet source code, with a goal being run in the parent project: mvn liferay:build-service...so the dependency is affected by the source code of the portlet app (sounds a little crazy). That was a tricky part in my case.
So how do we get the service dependency built and deployed for the service portlet to use it?
Well, the solution for this was using a configuration within the maven-release-plugin that allows Maven to run particular goals in the release:perform phase within any of the projects. What I did is adding this configuration in the maven-release-plugin declaration in the parent pom.xml (Service Layer):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.2</version>
<configuration>
<goals>clean liferay:build-service deploy</goals>
</configuration>
</plugin>
And Maven was able to deploy the parent and each of the children modules with our preferred version numbers (you will be asked to input them).
Summarized answer and recommendation: try using the <goals> configuration and run mvn release:prepare and mvn release:perform at the parent level
Parent and modules should be deployed following the order.
I hope this inspires someone in a similar situation at least, after 5 years.
For the multi module project, when it fails for child snapshot dependency try this
release:clean release:prepare release:perform -DignoreSnapshots=true
Hope it helps.

Resources