Maven including older version of spring - maven

I have a maven project in eclipse with m2e plugin. Dependency hierarchy is showing it is omitting spring 3.2.3 in place of 3.0.0.RELEASE as shown below. How to do it otherwise? Should it not omit the older version and keep the latest?

Maven works on the principle of nearest wins strategy while resolving the dependency conflicts , that means whichever version it finds nearer in the tree , it will take that version and ignore the other versions.
In your case when you can run -
mvn dependency:tree -Dverbose -Dincludes=spring-aop
You will notice that in the tree hierarchy version 3.0.0 is coming earlier in comparison to version 3.2.3 , so that's why it is taking version 3.0.0 version for resolving the dependency.
Solution : As a recommended solution to these types of problem is have a proper dependency management in your parent pom.xml file. Like in your case you can have something lik e this :
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>3.2.3</version>
</dependency>
<dependencies>
</dependencyManagement>
Now no matter what whenever Maven try to resolve the version for spring-aop , it will always consult the dependency management and will use the version defined under dependencyManagement.
For more you can refer here on my blog: how maven resolves dependency conflicts

Related

IntelliJ How to force downgrade dependency version?

I have a persistent problem with maven dependencies version changes in IntelliJ. Whenever I try to use a previous version of a library and change the dependency version in my pom.xml nothing happens. Maven continues to use the newer version of the library.
For example I want to use:
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
But Maven repo has version 2.0.2 saved :
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
So for my projects version 2.0.2.RELEASE is used.
I tried reimporting the project first. Then I tried "reimpor all maven projects". Then I checked Settings > Maven > Always update snapshots. I also tried opening the project settings and deleting the dependency from there, but on reimport the 2.0.2 version will be imported in the project. For now the only thing that works is deleting manually the folder from the ".m2" folder.
Shouldn't library versions be strictly followed and shouldn't version 2.0.1 v be used for my project?
The moment you change the version of the artifacts, maven will use the same version. It will never use neither new version nor the older version. Since you are using intellij, you can check which are the jar files along with their version used. See below the screenshot.
You can expand the External libraries as shown below and you can check the dependencies used in pom.xml.
Besides, you can also check in command prompt. Go to command prompt and point to the project directory and type the following command.
mvn install dependency:copy-dependencies
You can see all the required dependencies along with version information in target folder.
I suggest you not to delete the .m2 directory as you may have to download all the dependencies once again.
If you want to enforce the use of a particular dependency version you can use:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.0.1.RELEASE</version>
</dependency>
</dependencies>
</dependencyManagement>
What this will do is exclude the dependency unless it actually gets used, and then if it does gets used it only uses the version you have specified.
Not clear what is the issue.
Repo can contain everything, no matter if dependency is present locally.
Also, Idea does not resolve dependency itself, we use maven api to resolve them.
By default, maven takes dependency which is nearest to root (see https://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html)
Specifiying explicit dependency in root pom should force using this version.
Could you please provide mvn dependency:tree output and corresponding IDEA maven dependency diagram (if you have IU)?
If Idea resolve another dependency version than maven, please fill an issue at https://youtrack.jetbrains.com/issues

Getting Maven to resolve missing dependencies with closest available matches

When I look at my local Maven cache (~/.m2/repository/) I see 10-20 versions of certain artifacts, some of which are being used for only a single specific build (project). I would like to get rid of this duplication (true, they are different versions, but I'd still think a depending project would be able to tolerate a micro or minor version difference) and to somehow ask Maven to resort to the closest available version during dependency resolution, if a specific artifact version is missing in the local repository.
For example, if I have versions 1.0.0, 1.1.2, 1.4.0 and 2.0.0 of a foo:bar artifact in my local cache, I would like Maven to:
use 1.1.2 for a build requiring 1.1.0
use 1.4.0 for a build requiring 1.4.10
use 2.0.0 for a build requiring 2.5.0
without having to manually change the pom of the specific build(s).
I am fairly aware of the risks associated with switching dependency versions without proper analysis, and I'm only asking for a mechanism to be utilized for non-critical builds (such as a tool/library that I just cloned off a VCS, and would like to run and try out), preferably activated only when a particular flag is provided.
Is there something out there, like a Maven extension or plugin (that can be applied on a system-wide scale, and activated on demand with a flag), that can help me achieve my goal?
P.S.: Since the definition of "closest" could be ambiguous (given the fact that Maven may not know which of 1.4.0 and 2.0.0 is closer to 1.5.0 depending on the actual release versions lying between them), it would even be sufficient if I can specify the version on the build command (e.g. mvn package -Dfoo:bar=1.4.0), still without making any manual pom changes. (While this may already be possible for versions that have been specified as <properties> entries, I would like a generic solution where even hard-coded versions in transitive dependencies could be overridden.)
P.P.S.: Please note tht the project(s) that would be built would not have been authored/composed by me, so I don't really have control/authority over their actual pom files. What I'm looking for is a way to override dependency versions in their pom files without doing any manual modifications at source level.
In order to change a transitive dependency, you need to exclude the transitive dependency in your direct dependency, then add a direct dependency in your pom.
For example, if you have a dependency on foo.jar (which depends on xyz.jar version 1.3) and on bar.jar (which depends on xyz.jar version 1.4), you can have these two sections in your pom:
<!-- Define the version(s) that you allow your dependencies to depend on. -->
<dependencyManagement>
<dependency>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
<version>[1.0,2.0)</version>
</dependency>
<dependency>
<groupId>projectFoo</groupId>
<artifactId>foo</artifactId>
<version>1</version>
<exclusions>
<exclusion>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>projectBar</groupId>
<artifactId>bar</artifactId>
<version>5</version>
<exclusions>
<exclusion>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencyManagement>
...
<!-- Declare your dependencies but don't allow them to suck in their transitive dependencies. -->
<dependencies>
<dependency>
<groupId>projectXyz</groupId>
<artifactId>xyz</artifactId>
</dependency>
<dependency>
<groupId>projectFoo</groupId>
<artifactId>foo</artifactId>
</dependency>
<dependency>
<groupId>projectBar</groupId>
<artifactId>bar</artifactId>
</dependency>
</dependencies>
...
This will pick up the most recent version of xyz.jar that it can, and that will be the only version used. When foo and bar use xyz, they'll have the version that you've allowed into your project.
The best thing to do is to use a parent pom (or bom: bill of materials) with a well-defined and well-maintained dependencyManagement section. Stick with a single version of everything, just share that "everything" between all projects. You can override versions in projects if you need to.
If you'd rather define versions in each project, then version ranges will work. For the three examples you gave, you would use things like:
[1.1.0, 1.2)
[1.4.0, 1.5)
[2.0.0,)
(Open to correction here.. I haven't used version ranges in almost 10 years.)
Finally, to get it to use versions that are already available, rather than download the best ones, all you can do is to use a local artifact repository as your central maven repository, and turn off access to maven central and bintray.
Closest thing I found so far: https://github.com/jboss/maven-dependency-management-extension/blob/master/README.md
It can be dropped into ${MAVEN_HOME}/lib/ext and utilized for overriding versions of specific dependencies, e.g. mvn install -Dversion:junit:junit=4.10. While it doesn't offer the suggested "intelligent version derivation" approach, it's a good-enough solution.

How's maven resolving the slf4j dependency of spring data gemfire?

Spring data gemfire 1.7.0.RELEASE has compile time dependencies on version 1.7.12 of slf4j-api and jcl-over-slf4j. I have defined the below dependencies in my maven pom file, as we need slf4j 1.7.10 dependency (few other jars depend on this):
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
<version>1.7.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.10</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.10</version>
<scope>runtime</scope>
</dependency>
I have an internal maven repo as the Maven central repository. Below is the behavior I see in different scenarios, based on what jars are available in the maven central:
My questions:
In scenario 1, I don't understand why the build didn't complain about missing 1.7.12 jar. How did the dependency get resolved?
In scenario 2, how's the 1.7.10 jar overriding the 1.7.12 without me specifying an exclusion for slf4j 1.7.12 in the spring data dependency?
In scenario 3, when the pom for slf4j-parent 1.7.12 is missing in Maven central, why does it complain? Since 1.7.10 jars are present, shouldn't the build run fine picking up the 1.7.10 jars (similar to scenario 1)?
The answer is based on the Maven Dependencies Mediation mechanism, specifically this statement:
You can always guarantee a version by declaring it explicitly in your project's POM
So, essentially, by explicitly declaring it as part of your dependencies, you are overriding any version on transitive dependencies, as such you don't need to add any exclusion. You declare it, you have the knowledge of the project, Maven trusts you.
So in scenario 1 and 2 Maven applied the rule above and just followed what is specified in the POM.
In scenario 1, since it didn't find any 1.7.12 version at all, it even didn't try to resolve it and trusted your POM.
In scenario 2, it resolved the dependencies tree of 1.7.12, but then based on your POM, the version 1.7.10 won.
In scenario 3 it couldn't resolve the whole dependency tree of version 1.7.12 and as such it gave an error: yes, the version from your POM would have won anyway, but since Maven had an error on getting the full dependency tree, it then failed its execution.
This is a special case though, and final confirmation could only be given looking at the concerned code of the Maven version you are using.
Update
What I would suggest to try in the three scenarios to have a bit more of details, is to run from the console:
mvn dependency:resolve -Dsort=true -X
Thanks to the debug flag, it will provide a list of included and excluded dependencies during the Dependency Mediation process.
As a complement, running:
mvn dependency:tree
Would give you the full dependency graph, showing what was actually taken from the POM and what came through transitive dependencies. That might give you further info. For further details, I would suggest to have a look at the Maven Dependency Plugin goals.

Force latest version for maven dependencies

I have the following dependency (only so far) pom.xml
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>1.6.2.RELEASE</version>
</dependency>
This dependency obviously depends on other "dependencies" via it's pom.xml... when maven finished downloading these dependencies I noticed that it didn't grab the latest version of the Spring stuff (4.0.6.RELEASE)... it grabbed a 3.2.x version.
How can I force maven to grab the latest version of the Spring stuff? Do I need to explicitly modify my pom.xml to include all the dependencies or is there some "magic" I can use for this?
Thanks.
Spring "Bill Of Materials"
Salvation may come from special "bill of materials" POMs supported by Maven and published by Spring. Quoting from Maven "Bill Of Materials" Dependency in their manual:
It is possible to accidentally mix different versions of Spring JARs when using Maven. For example, you may find that a third-party library, or another Spring project, pulls in a transitive dependency to an older release. If you forget to explicitly declare a direct dependency yourself, all sorts of unexpected issues can arise.
To overcome such problems Maven supports the concept of a "bill of materials" (BOM) dependency. You can import the spring-framework-bom in your dependencyManagement section to ensure that all spring dependencies (both direct and transitive) are at the same version.
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-framework-bom</artifactId>
<version>4.0.6.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Would this work for you?
Looking at the spring-data-jpa artifact pom file, we can see that it has a parent called spring-data-parent with current version 1.4.2.RELEASE. It's pom describes dependencies and their versions. Currently spring version is at 3.2.10.RELEASE
One way you can possibly accomplish what you want is to add explicit dependency on spring artifacts. But you would still have to define their versions.

dependencyManagement in parent ignored

I have a project, P1, that creates a jar. That project has a parent POM, P1-PARENT. P1-Parent includes the following:
<dependencyManagement>
<!-- Kafka uses Zookeeper 3.3.4, but Curator requires 3.4.5. To resolve
we specify 3.4.5 so all projects using either Kafka or Curator will
get the later version which is compatible with both projects. -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.4.5</version>
</dependency>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka_2.10</artifactId>
<version>0.8.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-client</artifactId>
<version>2.2.0-incubating</version>
</dependency>
<!-- A bunch of other irrelevant stuff here -->
</dependencyManagement>
This works - the output of "mvn dependency:tree" includes:
[INFO] +- org.apache.kafka:kafka_2.10:jar:0.8.0:compile
[INFO] | +- org.apache.zookeeper:zookeeper:jar:3.4.5:compile (version managed from 3.3.4)
Note that this is the only dependency on zookeeper (verified via "mvn dependency:tree | grep zoo".
I have several other projects that also inherit from P1-PARENT and everything works fine, they all pull in ZooKeeper 3.4.5. However, A coworker of mine recently starting using P1 in one of their projects. Their project doesn't inherit from P1-PARENT. The transitive dependency they get from P1 is ZooKeeper 3.3.4, not 3.4.5. We have verified, via "mvn dependency:tree", that they get zookeeper.3.3.4 as a transitive dependency of Kafka (e.g. the output looks identical to what I've pasted above, but the version is 3.3.4 and it doesn't include the "(version managed ..." bit). Also, like my projects, the only dependency they have on ZooKeeper (transitive or otherwise) is through P1 (verified by dependency:tree and grep). The question is, why. When they include P1, shouldn't maven look at P1's parent POM when determining the transitive dependencies of P1?
I'm using Maven 3.0.5. They're using versions 3.0.3 and 3.1.1 and see the problem with both of those versions.
Maven doesn't resolve the version transitive dependency issue in this case.
This issue can be used by using maven bom concept.
Check the maven documentation for bom in the below link
http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Management
Here is another blog which explains usage of bom's
http://howtodoinjava.com/maven/maven-bom-bill-of-materials-dependency/
In your case to solve this issue, you need to add a dependency of your parent pom in the dependencyManagement section of other project where you are facing the issue.
When using Maven3, ensure you're using the right version of the maven-dependency-plugin by calling it by its fully qualified name: org.apache.maven.plugins:maven-dependency-plugin:2.8:tree. IIRC up to 2.6 gave a wrong tree. In such cases the advice was: run your project as 'mvn validate -X' to see the tree as resolved by Aether, the dependency management framework for Maven.

Resources