20

Can I configure Maven to choose the "newest" dependency on a conflict, rather than the "nearest"?

The "newest" is the default in Ivy and other sensible dependency managers, see http://ant.apache.org/ivy/history/2.2.0/settings/conflict-managers.html

I find the "nearest" strategy is rarely what I want.

I'm using Maven 3.3.3, but I can switch versions if necessary.

I know how to override Maven's choice on individual conflicts, but I'd prefer to change the default so that I don't have to detect and fix each conflict one at a time.

(See the Maven docs on "Dependency mediation")

Rich
  • 15,048
  • 2
  • 66
  • 119
  • 1
    If you say that you rarely don't want is one opinion. As far as i know there no simple way to change this behaviour...What you can do is to provide a patch which changes the behaviour in Maven Core...To detect such things you can use enforcer rules to identify such situations.... – khmarbaise Dec 10 '15 at 13:27
  • 2
    [This discussion](http://maven.40175.n5.nabble.com/Adding-support-for-new-dependency-mediation-strategy-td5768185.html) on a previous attempt to add this functionality to Maven is worth a read. – heenenee Mar 30 '17 at 06:15
  • 3
    Thanks, @heenenee. I see now why Maven hasn't evolved at all in the last 10 years or so, it seems to be completely moribund. Maybe I'll try to switch my project to SBT, which has newest-wins dependency conflict resolution and can consume Maven deps and is supported by IntelliJ. – Rich Mar 30 '17 at 07:58
  • 2
    @Rich I pulled out the most relevant parts of the discussion into an answer. I don't usually answer questions with a "no", but I felt it's warranted in this case. When inheriting source code, I'm usually happy if it's a Maven project because the build is easily understood (in no small part because Maven evolves so slowly), however I'm usually starting my own new projects with Gradle. You should use whatever works best for you and your team; if that's SBT, then go for it. – heenenee Apr 02 '17 at 07:27
  • @Rich, the `newest` strategy is really bad. It may work for a well managed simpler project; But in deep trees of unmaintained in-house libraries mixed with actively developed ones demanding the newest stuff, this leads to compilation errors, and worse, *runtime errors*. That said, I'm not happy with `nearest first` either. I would like to have `nearest highest`, taking the highest version from the nearest level where it is defined. It makes sense: If you run into issues, typically you simply downgrade. With "newest", that is not possible, and you need to `force`, which is a hack. – Ondra Žižka Apr 16 '23 at 00:42
  • By the way, did your effort result into a Maven extension? – Ondra Žižka Apr 16 '23 at 00:43
  • @OndraŽižka : I don't think it's "really bad". I have been using it on many very large Maven projects in commercial development for many years. It's also the default in newer java dep management systems like SBT and Gradle. Your circumstances and preferences may differ, of course. If you have deep trees of binary incompatible mixed dependencies then you will have big problems with both "nearest" and "newest" auto conflict resolution strategies. I have not written a Maven extension for this; I use the "requireUpperBoundDeps" rule instead, see my answer below. – Rich Apr 19 '23 at 09:56

2 Answers2

18

Can I configure Maven to automatically use the "newest" version of a dependency instead of the "nearest" when resolving version conflicts?

No, you cannot configure Maven's dependency mediation strategy to anything other than nearest.

Adding configurable dependency mediation strategies has been proposed before, but was ultimately abandoned because the proposal involved changing the POM XSD, which has not happened in years.

Why does Maven use the nearest strategy as a default?

The strategy of nearest is favored by Maven for two reasons:

  1. Easy overriding of individual conflicts: For any particular conflicting dependency, you can specify its version within your own POM, and that version becomes the nearest.
  2. Reproducible builds: Version ranges anywhere in your dependency graph can cause builds to not be reproducible. A mediation strategy of "newest" would magnify the negative impact of version ranges on build reproducibility.

But I really want a different dependency mediation strategy. What can I do?

These are your best options:

  1. Make a Maven extension: Usage of the "nearest" strategy is specified by NearestVersionSelector in MavenRepositorySystemUtils. You could create your own Maven extension that defines your own VersionSelector that implements the strategy of your choice, then in the afterSessionStart method of your extension, replace the session's DependencyGraphTransformer with one that uses your custom VersionSelector.
  2. Migrate to another build tool: Obviously.
heenenee
  • 19,914
  • 1
  • 60
  • 86
  • Thanks. Could a build plugin not override this behaviour? That would give a path to changing this without changing the POM XSD. – Rich Apr 02 '17 at 21:09
  • This comment suggests that a build plugin cannot change dependencies: "Maven 3.x introduced changes in dependency resolution that makes it impossible for this plugin to function optimally. In Maven 3.x all dependencies are resolved before the lifecycle phases are started, making it impossible for a plugin to download and install the external dependencies before Maven resolves the project's dependencies." https://github.com/UniversalMediaServer/external-maven-plugin#external-dependency-maven-plugin – Rich Apr 03 '17 at 19:27
  • What is this class for? https://github.com/apache/maven/blob/master/maven-compat/src/main/java/org/apache/maven/repository/legacy/resolver/conflict/NewestConflictResolver.java – Rich Apr 03 '17 at 19:32
  • @Rich that class is for Maven 2. – heenenee Apr 03 '17 at 19:39
  • 1
    @Rich as you quoted, plugins don't execute at a time where it is possible to change the conflict resolution strategy, so a plugin to do this is not viable. However, you can make a Maven extension, so I've updated my answer accordingly. – heenenee Apr 03 '17 at 19:42
  • 1
    **Worth highlighting**: `AbstractMavenLifecycleParticipant.afterSessionStart` is not invoked when declared as a build `` or via a plugin's ``, must be in [${maven.home}/lib/ext](https://maven.apache.org/ref/3.5.4/maven-embedder/core-extensions.html) or [${maven.projectBasedir}/.mvn/extensions.xml](https://maven.apache.org/ref/3.5.4/maven-embedder/core-extensions.html). Only in `afterSessionStart` is `session.getRepositorySession()` modifiable, by the time `afterProjectsRead` is invoked it's read-only. – earcam Oct 06 '18 at 19:04
  • 1
    It's worth noting that "newest" means the _oldest_ version that satisfies all the dependencies. It's not the newest release or anything like that. It should not cause non-reproducible builds in case of simple dependencies. For ranges, Maven can just fallback to the original behavior. Very disappointing. – proski Jul 12 '19 at 22:58
5

You can also use the "requireUpperBoundDeps" rule for the Maven "enforcer" plugin, which will not directly implement a "newest wins" conflict resolution policy, but will enforce that the end result is the same. You will need to manually add transitive dependency <exclusions> or <dependencyManagement> rules to your POM to choose the newest dependency in each conflict, but at least you will then have confidence that the end result is "newest wins".

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>1.4.1</version>
    <executions>
      <execution>
        <id>enforce</id>
        <configuration>
          <rules>
            <requireUpperBoundDeps />
          </rules>
        </configuration>
        <goals>
          <goal>enforce</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
Rich
  • 15,048
  • 2
  • 66
  • 119