Skip to end of metadata
Go to start of metadata

Conflict Resolvers

Synopsis

A dependency version conflict occurs when building a Maven project whose dependency graph pulls in two different versions of the same dependency. Maven must decide which version of the conflicting dependency to use before proceeding with the build. The behaviour thus far has always been to select the version in the dependency graph that is 'nearest' to the project being built, where the distance is defined to be the number of transitive steps between two nodes in the graph. This aim of this proposal is to allow alternative conflict resolution techniques to be used when building projects with Maven.

 Design

The existing but unused ConflictResolver interface will become the basis for the conflict resolver API. The following method will be added to handle conflict resolutions:

The following ConflictResolver implementations will be provided:

Name

Strategy

nearest

Resolves conflicting artifacts by always selecting the
nearest declaration. Nearest is defined as the declaration that has
the least transitive steps away from the project being built.

farthest

Resolves conflicting artifacts by always selecting the
farthest declaration. Farthest is defined as the declaration that has
the most transitive steps away from the project being built.

newest

Resolves conflicting artifacts by always selecting the
newest declaration. Newest is defined as the declaration whose version
is greater according to ArtifactVersion.compareTo.

oldest

Resolves conflicting artifacts by always selecting the
oldest declaration. Oldest is defined as the declaration whose version
is less according to ArtifactVersion.compareTo.

ArtifactCollector will have an additional method added to accept a list of ConflictResolvers:

Correspondingly, DefaultArtifactCollector will be updated to process the chain of ConflictResolvers to resolve dependency version conflicts. The chain will be processed until one ConflictResolver can resolve the conflict. In the event that no ConflictResolvers can resolve the conflict, an ArtifactResolutionException will be thrown to fail the build.

ArtifactResolver will also have a corresponding new method in order to delegate to the new ArtifactCollector method:

To ensure that the conflict resolution strategy is consistent throughout the build, all usages of ArtifactCollector and ArtifactResolver within Maven will be updated to use these new overloaded versions. The list of ConflictResolvers to use will be obtained from the MavenProject being built. In order to preserve the 2.0.x POM schema, a POM property will initially be used to configure the ConflictResolver chain. The POM property will be named mavenConflictResolvers and its value will be defined as a comma-separated list of conflict resolver names. For example:

For 2.1.x, it is likely that the POM schema will be modified to introduce a more appropriate syntax for configuring conflict resolvers. For example:

For backwards compatibility, if a project does not declare any conflict resolvers then the 'nearest' conflict resolver will be used by default.

  • No labels

5 Comments

  1. I'd suggest to add also a conflict-resolution method 'fail' which causes a build to fail id two different versions of an artifact are referenced. Generally this would enforce updating the project basing on an older version.

     Ideally, I should be able to set the 'fail' mode only for dependencies of a set of projects, e.g. those with group-id matching org.example.*.

  2. why do not allow the user to specify explicitly the compatibility of artifact versions so maven could decide to choose the latest version if it is backward-compatible ? and to fail the build process in the case of non-compatibility with a readable error message

  3. It would be helpful to also have a way to load a custom conflict resolvers as an extension.  Maybe the custom resolver could have it's name defined internally, and then you could choose to use it by doing something like:

    <dependencies>
        <conflictResolvers>
            <conflictResolver>newest</conflictResolver>
            <conflictResolver>myCustomResolver</conflictResolver>
            <conflictResolver>nearest</conflictResolver>
        </conflictResolvers>
    </dependencies>
    
  4. Mark, do you have an example of when you would want to use more than one conflict resolver? It seems like only one would ever be needed for a single build.

  5. How would ConflictResolvers interact with VersionRanges?  The current behavior of maven when a one or more VersionRanges is introduced is to select the highest numbered version available in the repository which lives in the intersection of all VersionRanges.  Would a ConflictResolver override this behavior, or be overridden by it?