Maven dependency convergence error

I use the maven-enforcer-plugin to check for dependency convergence issues. A typical output would be: [WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence failed with mess...

We all agree that JUnit should never be set to another scope than test. Generally speaking I don’t think either that there is another solution than excluding the unwanted dependency, so we all agree that your are right to do it.

A SIMPLE CASE :

As Andreas Krueger says, there may be a risk with versions (I actually encountered it). Let say that the project’s dependencies are the following:

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:2.0
     +-group2:projectB:3.8.1
  +-group2:projectB:4.11

Note that it is only a mere simplification of your case. Seeing this dependency tree, you would exclude the dependency projectB given by projectA :

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>2.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>

After packaging the project with maven, the remaining dependency would be group2-someProjectB-4.11.jar, version 4.11 and not 3.8.1. Everything would be fine and the project would run without encountering any problem at all.

Then, a while after, let say that you decide to upgrade to the next version of project A, version 3.0 which adds new great features :

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>3.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>

The problem is that you are not aware yet that projectA version 3.0 also have upgraded its dependency projectB to version 5.0 :

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:3.0
     +-group2:projectB:5.0
  +-group2:projectB:4.11

In that case, the exclusion you would have made a while ago excludes projectB version 5.0.

However, projectA version 3.0 needs the improvements from project B version 5.0. Because of the exclusion, after packaging the project with maven, the remaining dependency would be group2-someProjectB-4.11.jar, version 4.11 and not 5.0. At the moment you use any of projectA’s new features, the program wouldn’t run correctly.

WHAT WAS THE SOLUTION ?

I encountered this problem in a Java-EE project.

A team developped database services. They packaged it as projectA. Each time they updated the services, they also updated a file listing all their current dependencies and the current versions.

ProjectA was a dependency for the Java-EE project I was working on. Each time the service-team updated ProjectA, I also checked the versions’ updates.

In fact, there is no harm in excluding a dependency. But each time you update a dependency where an exclusion has been set, You have to check :

  • if this exclusion still makes sense.
  • if you need to upgrade the version of the excluded dependency in your own project.

I guess maven exclusions are like kitchen knifes. It’s sharp, cuts vegetables with no effort, but requires care when handling it…

Join the DZone community and get the full member experience.

Join For Free

I was running in to a problem with a Java project that occured only
in IntelliJ Idea, but not on the command line, when running specific
test classes in Maven. The exception stack trace had the following in
it:

Caused by: com.sun.jersey.api.container.ContainerException: No WebApplication provider is present

That seems like an easy problem to fix — it is the exception message
that is given when jersey can’t find the provider for JAX-RS. Fixing it
is normally just a matter of making sure jersey-core is on the
classpath to fulfill SPI requirements for JAX-RS. For some reason
though this isn’t happening in IntelliJ Idea. I inspected the log
output of the test run and it is quite clear that all of the jersey
dependencies are on the classpath. Then it dawns me on the try running mvn dependency:tree from inside of Idea. Here is what I found:

[INFO] +- org.mule.modules:mule-module-jersey:jar:3.2.1:provided
[INFO] |  +- com.sun.jersey:jersey-server:jar:1.6:provided
[INFO] |  +- com.sun.jersey:jersey-json:jar:1.6:provided
[INFO] |  |  +- com.sun.xml.bind:jaxb-impl:jar:2.2.3-1:provided
[INFO] |  |  - org.codehaus.jackson:jackson-xc:jar:1.7.1:provided
[INFO] |  +- com.sun.jersey:jersey-client:jar:1.6:provided
[INFO] |  - org.codehaus.jackson:jackson-jaxrs:jar:1.8.0:provided
...
[INFO] +- org.jclouds.driver:jclouds-sshj:jar:1.4.0-rc.3:compile
[INFO] |  +- org.jclouds:jclouds-compute:jar:1.4.0-rc.3:compile
[INFO] |  |  - org.jclouds:jclouds-scriptbuilder:jar:1.4.0-rc.3:compile
[INFO] |  +- org.jclouds:jclouds-core:jar:1.4.0-rc.3:compile
[INFO] |  |  +- net.oauth.core:oauth:jar:20100527:compile
[INFO] |  |  +- com.sun.jersey:jersey-core:jar:1.11:compile
[INFO] |  |  +- com.google.inject.extensions:guice-assistedinject:jar:3.0:compile

Notice how I have jersey-core 1.11 coming from jclouds-core but
jersey 1.6 everywhere else. That, my friends, is a dependency
convergence problem. Maven with its default set of plugins (read: no
maven-enforcer-plugin) does not even warn you if something like this
happens. In this case, somehow jclouds-core depends directly on
jersey-core and happens to resolve the dependency to the version that
jclouds-core declared first before jersey-core can be resolved as a
transitive dependency on mule-module-jersey.

To fix the symptom, all I had to do was add the jersey-core dependency explicitely as a top level dependency in my pom:

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-core</artifactId>
    <version>${jersey.version}</version>
    <scope>provided</scope>
</dependency>

But doing so only fixes the symptom, not the problem. The real problem
is that the maven project I’m working on does not presently attempt to
detect or resolve dependency convergence problems. This is where the maven-enforcer-plugin comes in handy. You can have the enforcer plugin run the DependencyConvergence
rule agaisnt your build and have it fail when you have potential
conflicts in your transitive dependencies that you haven’t resolved
through exclusions or declaring direct dependencies yet. Binding the
maven-enforcer-plugin to your build would look something like this:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-enforcer-plugin</artifactId>
            <version>1.0.1</version>
            <executions>
                <execution>
                    <id>enforce</id>
                    <configuration>
                        <rules>
                            <DependencyConvergence/>
                        </rules>
                    </configuration>
                    <goals>
                        <goal>enforce</goal>
                    </goals>
                    <phase>validate</phase>
                </execution>
            </executions>
        </plugin>
    </plugins>
...
</build>

I chose to bind to the validate phase since that is the
first phase to be run in the maven lifecycle. Now my build fails
immediately and contains very useful output that looks like the
following:

Dependency convergence error for org.codehaus.jackson:jackson-jaxrs:1.7.1 paths to dependency are:
+-com.nodeable:server:1.0-SNAPSHOT
  +-org.mule.modules:mule-module-jersey:3.2.1
    +-com.sun.jersey:jersey-json:1.6
      +-org.codehaus.jackson:jackson-jaxrs:1.7.1
and
+-com.nodeable:server:1.0-SNAPSHOT
  +-org.mule.modules:mule-module-jersey:3.2.1
    +-org.codehaus.jackson:jackson-jaxrs:1.8.0

There are many rules you can apply besides DependencyConvergence. However, if the output from the DependencyConvergence
rule looks anything like mine does presently, it might take you a while
before you get around to getting your maven build to pass and conform
to other rules.

Dependency
Apache Maven

I’ve got this strange problem and I have no clue what’s the problem.

I have a multi-module java maven project with a structure like this:

+ A (parent)
+-+-B
| +--C
| +--D

I added a dependency in the parent pom (A):

  <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>1.8.5</version>
            <exclusions>
                <exclusion>
                    <groupId>com.mchange</groupId>
                    <artifactId>c3p0</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.mchange</groupId>
                    <artifactId>mchange-commons-java</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

Note: Version 1.8.5 is necessary for other modules beside A

In modules C and D it is necessary to use version 2.3.0, so i override version 1.8.5 from parent pom A with this dependency:

 <dependency>
        <groupId>org.quartz-scheduler</groupId>
        <artifactId>quartz</artifactId>
        <version>2.3.0</version>
        <exclusions>
            <exclusion>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
            </exclusion>
            <exclusion>
                <groupId>com.mchange</groupId>
                <artifactId>mchange-commons-java</artifactId>
            </exclusion>
        </exclusions>
    </dependency>

I added this dependecy in the poms of module C and D. C is also a dependency of D. So when i try to build the project, i get following error:

[WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence   failed with message:
Failed while enforcing releasability the error(s) are [
Dependency convergence error for org.quartz-scheduler:quartz:1.8.5 paths to dependency are:
+-de.xxx.xxx.xxx:module-D:6.40.1-jat-SNAPSHOT
  +-de.xxx.xxx.xxx:module-C:6.40.1-jat-SNAPSHOT
    +-org.quartz-scheduler:quartz:1.8.5
and
+-de.xxx.xxx.xxx:module-D:6.40.1-jat-SNAPSHOT
  +-org.quartz-scheduler:quartz:2.3.0

So somehow maven thinks the version of quartz of Module C is 1.8.5 but i explicitly set the version in the pom of module C to 2.3.0

also when i run mvn dependency:tree -Dverbose in the directory of module C, it seems correct: [INFO] +- org.quartz-scheduler:quartz:jar:2.3.0:compile

Does anybody has any idea?


Module A (the parent) must have a packaging type of pom.

In general it is a bad idea to declare dependencies in parent poms because it forces all child modules to have these specific dependencies whether they are needed or not. It is the equivalent of declaring these dependencies in every child module.

When modules C and D come into play you then have the equivalent of duplicate dependency declarations with conflicting versions.

Instead, module A should use a <dependencyManagement> section to declare dependency versions without forcing every child module to actually be dependent upon them.

In other words:

<dependencyManagement>
    <dependencies>
        ...
        <dependency>
           <groupId>org.quartz-scheduler</groupId>
           <artifactId>quartz</artifactId>
           <version>1.8.5</version>
           <exclusions>
               <exclusion>
                  <groupId>com.mchange</groupId>
                  <artifactId>c3p0</artifactId>
               </exclusion>
               <exclusion>
                   <groupId>com.mchange</groupId>
                   <artifactId>mchange-commons-java</artifactId>
               </exclusion>
           </exclusions>
        </dependency>
        ...
    </dependencies>
</dependencyManagement>

The quartz dependency declarations in modules C and D will then simply override the version specified in the parent A.

Other modules that are dependent upon the managed quartz library will still need to explicitly declare it:

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
</dependency>

where the version and exclusions will be picked up from the managed dependency declaration.

Or how to escape the dependency hell by detecting dependency convergence with the maven enforcer plugin.

Dependency con…what?

Consider the following scenario: Maven module M has a dependency to artifact A and B. A also has a dependency to artifact B. M needs B in version 1.0 and A needs B in Version 2.0:

M -+-> A -> B(2.0)
   |
   +-> B(1.0)

This is an example for dependency convergence.

Dependency Mediation

The JVM is not capable of handling different versions of library in the class path (assuming these versions share some packages / classes) in a deterministic way, that’s why maven will choose one single artifact version for you in case of dependency convergence.

This is achieved by a mechanism called dependency mediation (see Transitive Dependecies in Maven). If you think of the dependencies as a tree, the version of the artifact with the smallest distance to the root node will win. In our example this would be 1.0.
In most cases this strategy will do what we want, but what if A uses features of B that were not present in version 1.0? Well, then we’ll get some ugly RuntimeException as soon as this functionality is used. And we don’t want that, do we?

Detect Convergence

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-enforcer-plugin</artifactId>
  <version>1.0.1</version>
  <configuration>
    <rules>
      <DependencyConvergence/>
    </rules>
  </configuration>
  <executions>
    <execution>
      <id>enforce</id>
      <goals>
        <goal>enforce</goal>
      </goals>
      <phase>validate</phase>
    </execution>
  </executions>
</plugin>

This will cause the build fail in case of dependency convergence. The error message will look like this:

Dependency convergence error for org.codehaus.jackson:jackson-mapper-asl:1.9.2 paths to dependency are:
+-com.foo:foo-services:1.10.0.1-SNAPSHOT
  +-com.foo.messaging.abstractJmsClient:DefaultJmsClient:1.4.0
    +-com.foo.messaging.abstractJmsClient:JmsClients:1.4.0
      +-org.codehaus.jackson:jackson-mapper-asl:1.9.2
and
+-com.foo:foo-services:1.10.0.1-SNAPSHOT
  +-com.foo.cs.common:RonlAbstractMsg:2.40
    +-org.codehaus.jackson:jackson-mapper-asl:1.9.4

Take Control

When you encounter dependency convergence, you have to choose the artifact version that fits best for you. That depends on which features are used and in which version they are present. Usually the newest version will work quite well. Once you have decided which version to take, there are different ways to tell maven.

Dependency Management

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
</dependency>

to the dependency management section of your pom, if you should have decided for version 1.9.4.

Explicit Exclusion

Another possibility — if you should for some reason not want to employ dependency management — is to explicitly exclude the the undesired dependency an explicitly include the desired one. If you prefer that, you could in the above case add

<exclusions>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</exclusion>
</exclusions>

to the dependency transitively referencing the undesired version. You might (or might not) want to exclude it from all other dependencies referencing it, because then there won’t be a convergence if any those transitively referenced versions changes.
Don’t forget to then add

<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
</dependency>

to your pom, to explicitly reference the desired version. Otherwise you might end up missing a jar.

A Little Help

Especially when you introduce the enforcer plugin for the first time you will have to introduce a lot on new dependencies to your dependency management section / add a lot of exclusions and new dependencies depending on your approach. I’ve written a little python script to ease that up a little:

format_dependency.py on Google Drive

If called like this

./format_dependency.py org.codehaus.jackson:jackson-mapper-asl:1.9.4

it will output

formatting org.codehaus.jackson:jackson-mapper-asl:1.9.4


<exclusions>
<exclusion>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</exclusion>
</exclusions>


<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
</dependency>


<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
</dependency>

This might save you some time compared to typing it :-)

Specific version

I’ve left out the (rather not at all used) possibility of specific versions in maven [those in square brackets]. If you are interested in this topic have a look here:

  • Gunther Popp’s Blog: Understanding Maven Dependency Mediation (Part 1)
  • Gunther Popp’s Blog: Understanding Maven Dependency Mediation (Part 2)

Feedback …

is always appreciated! Please let me know if this was helpful or total crap. If you disagree or have any suggestions, you are very welcome to contact me as well!

Maven Enforcer Plugin is a plugin that helps you enforce rules such as which dependencies to use in your project, avoiding duplicate dependencies, banned dependencies and enforcing restrictions on transitive dependencies.

The plugin also provides goals to control certain environmental constraints such as Maven version, JDK version and OS family along with many more built-in rules and user created rules

This blog post will demonstrate how to use Maven Enforcer plugin in your project.

Log4j security vulnerabilities

In the month of December 2021, Apache Software Foundation disclosed 2 critical vulnerabilities, a Denial of Service condition ( CVE-2021-45046) and Remote Code Execution( CVE-2021-44228 ) that affects the Log4j logging library from versions 2.0-beta9 to 2.16.

The development teams all around the world have updated the vulnerable lo4j dependencies to 2.17.0 in response. As time passes, it will be forgotten and and we will proceed as normal. In the future a team member might add a dependency which has transitive dependency on vulnerable log4j version or we might add vulnerable log4j version if we are creating a new project.

We require a method to ensure that developers do not add vulnerable dependencies.

Maven enforcer plugin helps us to enforce the project rules.

I am going to demonstrate how to use below 4 rules with the help of enforcer plugin.

  • Enforce Banned Dependencies
  • Require Java Version
  • Require Maven Version
  • Dependency Convergence

Enforce Banned Dependencies

Due to security reasons or various other reasons organization or development team might have decided not to use certain jar dependencies or specific versions of jar files in the project.

We can configure enforcer plugin like below in pom.xml file to ban the selected dependencies/jars.

Below configuration fails the build if the project contain log4j-core dependencies below the version 2.17.0 in the project. It also checks for the transitive dependencies

<build> <plugins> .... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>block-vulnerable-log4j-versions</id> <phase>validate</phase> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <bannedDependencies> <excludes> <exclude>org.apache.logging.log4j:log4j-core:(,2.17.0)</exclude> </excludes> <searchTransitive>true</searchTransitive> </bannedDependencies> </rules> <fail>true</fail> </configuration> </execution> </executions> </plugin> </plugins> </build>

Code language: HTML, XML (xml)

[icon name=”clipboard” prefix=”fas”] Note

searchTransitive configutation is true by default.

If a developer tries to include a banned log4j-core dependency , enforcer plugin will fail the build phase.

Maven Enforcer Plugin

Banning dependencies follow the pattern of:

groupId[:artifactId][:version][:type][:scope][:classifier]

Everything after the groupId is optional.  The banned dependencies also follow the normal Maven pattern matching:

  • * or (*) – bans all versions of jar
<exclude>org.apache.logging.log4j:log4j-core:*</exclude>

<exclude>org.apache.logging.log4j:log4j-core:(*)</exclude>

Code language: Java (java)
  • [2.17,2.17.1] – matches the exact version within the brackets
  • <exclude>org.apache.logging.log4j:log4j-core:[2.17.0,2.17.1]</exclude>

    Code language: Java (java)
  • (,2.17.0) – matches all previous versions up to and excluding 2.17.0
  • <exclude>org.apache.logging.log4j:log4j-core:(,2.17.0)</exclude>
  • (2.17.0,) – matches all versions above 2.17.0 and excluding 2.17.0
  • <exclude>org.apache.logging.log4j:log4j-core:(2.17.0,)</exclude>

    Code language: Java (java)
  • [2.17.0,] – matches all versions above 2.17.0 and including 2.17.0
  • <exclude>org.apache.logging.log4j:log4j-core:[2.17.0,]</exclude>

    Banned dependencies rule can also be used to specify allow specific version of banned dependency in the project

    <includes> tag specifies the list of artifacts to include. These are exceptions to the excludes. It is meant to allow wide exclusion rules with wildcards and fine tune using includes. If nothing has been excluded, then the includes have no effect. To put it another way, <includes> tag only remove artefacts that meet an exclude rule.

    In below configuration, build will fail if maven dependencies include any version of log4j-core other than the 2.17.0

    <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>block-vulnerable-log4j-versions</id> <phase>validate</phase> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <bannedDependencies> <excludes> <exclude>org.apache.logging.log4j:log4j-core:*</exclude> </excludes> <includes> <include>org.apache.logging.log4j:log4j-core:2.17.0</include> </includes> <searchTransitive>true</searchTransitive> </bannedDependencies> </rules> <fail>true</fail> </configuration> </execution> </executions> </plugin> </plugins> </build>

    Code language: HTML, XML (xml)

    Require Java Version

    This rule enforces use certain Java JDK versions while building a project with Maven.

    Below configuration will fail if Maven uses JDK version less than 18.

    <build> <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>required-java-versions</id> <phase>compile</phase> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireJavaVersion> <version>18</version> </requireJavaVersion> </rules> <fail>true</fail> </configuration> </execution> </executions> </plugin> </plugins> </build>

    Code language: HTML, XML (xml)

    The RequireJavaVersion rules use the standard Maven version range syntax .Please refer to the table for rules.

    Require Maven Version

    This rule enforces certain Maven versions.

    <build> <plugins> .... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>required-maven-version</id> <phase>compile</phase> <goals> <goal>enforce</goal> </goals> <configuration> <rules> <requireMavenVersion> <version>(3.6,3.8)</version> </requireMavenVersion> </rules> <fail>true</fail> </configuration> </execution> </executions> </plugin> </plugins> </build>

    Code language: HTML, XML (xml)

    Dependency Convergence

    Version Range Specification

    The RequireMavenVersion and RequireJavaVersion rules use the below standard Maven version range syntax

    Range Meaning
    1.0 x >= 1.0 * The default Maven meaning for 1.0 is everything (,) but with 1.0 recommended. Obviously this doesn’t work for enforcing versions here, so it has been redefined as a minimum version.
    (,1.0] x <= 1.0
    (,1.0) x < 1.0
    [1.0] x == 1.0
    [1.0,) x >= 1.0
    (1.0,) x > 1.0
    (1.0,2.0) 1.0 < x < 2.0
    [1.0,2.0] 1.0 <= x <= 2.0
    (,1.0],[1.2,) x <= 1.0 or x >= 1.2. Multiple sets are comma-separated
    (,1.1),(1.1,) x != 1.1

    Dependency Convergence

    This rule requires that dependency version numbers converge. If a project has two dependencies, A and B, both depending on the same artifact, C, this rule will fail the build if A depends on a different version of C than the version of C depended on by B.

    To find out the dependency convergence issues, we should configure enforcer plugin like below

    <project> ... <build> <plugins> ... <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-enforcer-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <id>enforce</id> <configuration> <rules> <dependencyConvergence/> </rules> </configuration> <goals> <goal>enforce</goal> </goals> </execution> </executions> </plugin> ... </plugins> </build> ... </project>

    Code language: Java (java)

    Here is the sample example.

    If pom.xml contains

    <dependencies> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.6.0</version> </dependency> </dependencies>

    Code language: Java (java)

    Following error message will be logged during compilation

    Dependency convergence error for org.slf4j:slf4j-api1.6.1 paths to dependency are: [ERROR] Dependency convergence error for org.slf4j:slf4j-api:1.6.1 paths to dependency are: +-org.myorg:my-project:1.0.0-SNAPSHOT +-org.slf4j:slf4j-jdk14:1.6.1 +-org.slf4j:slf4j-api:1.6.1 and +-org.myorg:my-project:1.0.0-SNAPSHOT +-org.slf4j:slf4j-nop:1.6.0 +-org.slf4j:slf4j-api:1.6.0

    Code language: Java (java)

    To resolve the issue , we should exclude the dependency

    <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-nop</artifactId> <version>1.6.0</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions> </dependency>

    Code language: Java (java)

    Maven Enforcer Plugin ships with various other rules. Please check the documentation for all the rules. The plugin also provides maven-enforcer-rule-api to write your own custom rules. You can check sample custom rule implementation from the documentation page

    Adopting a Maven Enforcer Plugin will give project team members and company peace of mind and save the time and effort by enforcing predefined rules automatically.

    Мы все согласны с тем, что JUnit никогда не должен устанавливаться в другой области, кроме test. Вообще говоря, я не думаю, что есть другое решение, кроме исключения нежелательной зависимости, поэтому мы все согласны с тем, что вы правы в этом.

    ПРОСТОЙ СЛУЧАЙ:

    Как говорит Андреас Крюгер, может возникнуть риск с версиями (я действительно столкнулся с этим). Скажем, что зависимостями проекта являются следующие:

    +-foo:bar:1.0-SNAPSHOT
      +-group1:projectA:2.0
         +-group2:projectB:3.8.1
      +-group2:projectB:4.11
    

    Обратите внимание, что это всего лишь упрощение вашего дела. Если вы видите это дерево зависимостей, вы должны исключить проект зависимости b, заданный projectA:

    <dependency>
      <groupId>group1</groupId>
      <artifactId>projectA</artifactId>
      <version>2.0</version>
      <exclusions>
        <exclusion>
          <groupId>group2</groupId>
          <artifactId>projectB</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

    После упаковки проекта с maven оставшаяся зависимость будет group2-someProjectB-4.11.jar, версия 4.11, а не 3.8.1. Все будет хорошо, и проект будет работать без каких-либо проблем.

    Затем, спустя некоторое время, скажем, что вы решили перейти на следующую версию проекта A, версия 3.0, которая добавляет новые замечательные функции:

    <dependency>
      <groupId>group1</groupId>
      <artifactId>projectA</artifactId>
      <version>3.0</version>
      <exclusions>
        <exclusion>
          <groupId>group2</groupId>
          <artifactId>projectB</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

    Проблема в том, что вы еще не знаете, что версия ProjectA 3.0 также обновила проект зависимости b до версии 5.0:

    +-foo:bar:1.0-SNAPSHOT
      +-group1:projectA:3.0
         +-group2:projectB:5.0
      +-group2:projectB:4.11
    

    В этом случае исключение, которое вы бы сделали за последнее время, исключает версию projectB версии 5.0.

    Однако projectA версии 3.0 нуждаются в улучшениях от версии B версии 5.0. Из-за исключения, после упаковки проекта с maven, оставшаяся зависимость будет group2-someProjectB-4.11.jar, версия 4.11, а не 5.0. На данный момент вы используете какие-либо новые функции projectA, программа будет работать неправильно.

    ЧТО БЫЛО РЕШЕНИЕ?

    Я столкнулся с этой проблемой в проекте Java-EE.

    Команда разработала службы баз данных. Они упаковали его как projectA. Каждый раз, когда они обновляли службы, они также обновляли файл, в котором перечислены все их текущие зависимости и текущие версии.

    ProjectA был зависимым от проекта Java-EE, над которым я работал. Каждый раз, когда сервис-команда обновляла ProjectA, я также проверял обновления версий.

    На самом деле, нет никакого вреда для исключения зависимости. Но каждый раз, когда вы обновляете зависимость, в которой установлено исключение, вы должны проверить:

    • если это исключение все еще имеет смысл.
    • если вам нужно обновить версию исключенной зависимости в своем собственном проекте.

    Я думаю, что исключения maven похожи на кухонные ножи. Он острый, безрезультатно режет овощи, но требует осторожного обращения…

    I know I’m late to the party, but after scratching my head for 8-10 hours, I came around this solution which fixes the problem when you don’t have control over different poms where the different versions of dependencies are used at different places. So, I thought it’s worth sharing.

    @Gerold’s answer is an ideal one (source: Maven wiki). But, it works for the case when you are the owner of all the dependencies and have the time, luxury and write permission to fix the issue at the root. In my case, I was using a company-wide global parent pom which had different versions set in different places, so I was facing this issue. I wanted to find some way to fix this on my end without changing the global parent pom.

    To fix this, in your project’s parent pom, you can specify the exact version which matches with rest of the places and override the versions specified by the global parent poms at different places. You can add this block in your project’s parent pom

    <!-- ============================= -->
    <!-- DEPENDENCY MANAGEMENT -->
    <!-- ============================= -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>commons-collections</groupId>
                <artifactId>commons-collections</artifactId>
                <!-- This version should be consistent 
                     with versions at other places -->
                <version>3.2.2</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    HTH

    See POM Reference, Exclusions:

    Exclusions explicitly tell Maven that you don’t want to include the specified project that is a dependency of this dependency (in other words, its transitive dependency).

    See also Apache Maven Enforcer Rules, Dependency Convergence:

    If a project has two dependencies, A and B, both depending on the same artifact, C, this rule will fail the build if A depends on a different version of C then the version of C depended on by B.

    […]

    And this will succeed.

       <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-jdk14</artifactId>
          <version>1.6.1</version>
        </dependency>
        <dependency>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-nop</artifactId>
          <version>1.6.0</version>
          <exclusions>
            <exclusion>
              <groupId>org.slf4j</groupId>
              <artifactId>slf4j-api</artifactId>
            </exclusion>
          </exclusions>
        </dependency>
    

    Tags:

    Maven

    Maven 3

    Serenity Bdd

    Related

    Я использую Maven-enforcer-plugin для проверки проблем конвергенции зависимостей. Типичным выходом будет:

    [WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence failed 
      with message:
    Failed while enforcing releasability the error(s) are [
    Dependency convergence error for junit:junit:3.8.1 paths to dependency are:
    +-foo:bar:1.0-SNAPSHOT
      +-ca.juliusdavies:not-yet-commons-ssl:0.3.9
        +-commons-httpclient:commons-httpclient:3.0
          +-junit:junit:3.8.1
    and
    +-foo:bar:1.0-SNAPSHOT
      +-junit:junit:4.11
    ]
    

    видя это сообщение, я обычно «решаю» его, исключая транзитивную зависимость, например

    <dependency>
      <groupId>ca.juliusdavies</groupId>
      <artifactId>not-yet-commons-ssl</artifactId>
      <version>0.3.9</version>
      <exclusions>
        <!-- This artifact links to another artifact which stupidly includes 
          junit in compile scope -->
        <exclusion>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

    Я хотел бы понять, действительно ли это исправление и риски, связанные с исключением библиотек таким образом. Как я это вижу:

    • «исправление» обычно безопасно, при условии, что я выбираю использовать более новую версия. Это зависит от авторов библиотеки, поддерживающих обратную совместимость.

    • обычно нет никакого влияния на сборку Maven (так как более близкое определение выигрывает), однако, исключая зависимость, я говорю Maven, что я знаю об этой проблеме и, таким образом, успокаивая Maven-enforcer-plugin.

    верны ли мои мысли и есть ли альтернативный способ решения этой проблемы? Меня интересуют ответы, которые сосредоточены на общем случай-я понимаю junit пример выше немного странный.

    2 ответов


    мы все согласны с тем, что JUnit никогда не должен быть установлен в другую область, чем test. Вообще говоря, я не думаю, что есть другое решение, чем исключение нежелательной зависимости, поэтому мы все согласны с тем, что вы правы.

    ПРОСТОЙ СЛУЧАЙ:

    как говорит Андреас Крюгер, может быть риск с версиями (я действительно столкнулся с этим). Предположим, что зависимости проекта следующие:

    +-foo:bar:1.0-SNAPSHOT
      +-group1:projectA:2.0
         +-group2:projectB:3.8.1
      +-group2:projectB:4.11
    

    обратите внимание, что это просто упрощение вашего дела. Увидев это дерево зависимостей, вы исключите зависимость projectB, заданную projectA:

    <dependency>
      <groupId>group1</groupId>
      <artifactId>projectA</artifactId>
      <version>2.0</version>
      <exclusions>
        <exclusion>
          <groupId>group2</groupId>
          <artifactId>projectB</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

    после упаковки проекта с maven оставшаяся зависимость будет group2-someProjectB-4.11.jar, версия 4.11, а не 3.8.1. Все будет хорошо, и проект будет работать без каких-либо проблем.

    затем, через некоторое время, скажем, что вы решили перейти на следующую версию проекта A, версия 3.0, которая добавляет новые возможности :

    <dependency>
      <groupId>group1</groupId>
      <artifactId>projectA</artifactId>
      <version>3.0</version>
      <exclusions>
        <exclusion>
          <groupId>group2</groupId>
          <artifactId>projectB</artifactId>
        </exclusion>
      </exclusions>
    </dependency>
    

    проблема в том, что вы еще не в курсе что projectA версии 3.0 также обновили свою зависимость projectB до версии 5.0:

    +-foo:bar:1.0-SNAPSHOT
      +-group1:projectA:3.0
         +-group2:projectB:5.0
      +-group2:projectB:4.11
    

    в этом случае исключение, которое вы сделали бы некоторое время назад, исключает projectB версии 5.0.

    однако, projectA версии 3.0 нуждается в улучшениях от project B версии 5.0. Из-за исключения, после упаковки проекта с maven, оставшаяся зависимость будет group2-someProjectB-4.11.jar, версия 4.11, а не 5.0. На данный момент Вы используете любую из новых функций projectA, программа не будет работать правильно.

    КАКОВО БЫЛО РЕШЕНИЕ ?

    я столкнулся с этой проблемой в проекте Java-EE.

    команда разработала службы баз данных. Они упаковали его как projectA. Каждый раз, когда они обновляли службы, они также обновляли файл со списком всех своих текущих зависимостей и текущая версия.

    ProjectA была зависимостью для проекта Java-EE, над которым я работал. Каждый раз, когда команда службы обновляла ProjectA, я также проверял обновления версий.

    на самом деле, нет никакого вреда в исключении зависимости. но каждый раз, когда вы обновляете зависимость, в которой установлено исключение, вы должны проверить:

    • если это исключение все-таки есть смысл.
    • если вам нужно обновить версию исключена зависимость в вашем собственном проекте.

    Я думаю, исключения maven похожи на кухонные ножи. Он острый, режет овощи без усилий, но требует осторожности при обращении с ним…


    Если JUnit как артефакт проходит как зависимость в области компиляции, это ошибка одной из ваших библиотек, здесь: ca.juliusdavies.

    JUnit всегда должен быть включен в область тестирования. Таким образом, это не упакованный в произведенное .сосуд. ,война или. файл ear, при успешной сборке.

    вообще говоря, нет никакого вреда в исключении уже включенных зависимостей, например, когда библиотека 1 и библиотека 2 имеют одну общую зависимость.

    только проблема, конечно, может возникнуть, когда библиотека 1 и библиотека 2 включают разные версии одного и того же зависимого артефакта. Это может вызвать ошибки во время выполнения, когда функции библиотеки изменились.
    К счастью, это не так часто бывает, если разница в номерах версий не велика. В общем, рекомендуется включить последнюю версию зависимостей и исключить более старую. Это в большинстве случаев жизнеспособно.

    Если нет, проверьте, есть ли обновления зависимостей первого уровня вашего проекта.


    Понравилась статья? Поделить с друзьями:

    Читайте также:

  • Maven compiler plugin error
  • Maven compile error package does not exist
  • Matt exe error
  • Matrix ошибка обнаружения усо
  • Matlab has encountered an internal problem and needs to close ошибка

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии