Scenario: To make use of a new feature in a certain dependency or to get a bugfix that’s causing your project pain, you bump the version of a dependency in your pom file — maybe the parent pom version. Then you type
…put your hands over your eyes, and gingerly press Enter.
You may see something like this:
[WARNING] Rule 0: org.apache.maven.plugins.enforcer.RequireUpperBoundDeps failed with message: Failed while enforcing RequireUpperBoundDeps. The error(s) are [ Require upper bound dependencies error for org.slf4j:slf4j-api:1.7.11 paths to dependency are: +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-org.slf4j:slf4j-api:1.7.11 and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.netflix.hystrix:hystrix-core:1.5.4 +-org.slf4j:slf4j-api:1.7.11 (managed) < -- org.slf4j:slf4j-api:1.7.10 and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.example.framework:example-core:0.5.9-SNAPSHOT +-org.slf4j:slf4j-api:1.7.11 (managed) < -- org.slf4j:slf4j-api:1.7.7 and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.example.framework:example-core-data:0.5.9-SNAPSHOT +-org.slf4j:slf4j-api:1.7.11 (managed) < -- org.slf4j:slf4j-api:1.7.5 ...
…only it goes on for screens and screens. What happened?
What happened is your project wants one version of a dependency, but one or more of your project’s transitive dependencies want an incompatible version of the dependency.
More specifically, what happened is your project wants a lower version of a dependency, but one or more of your project’s transitive dependencies want a higher version of that dependency.
How to read the error output
In the error output for the maven enforcer plugin’s RequireUpperBoundDeps rule, when you see “(managed)” that means the version number specified by your project’s pom file. The version off to the right with an arrow pointing back at that is the version the transitive dependency wants.
Not everything in the report is an error; some are informational. For instance:
+-com.example.blah:blah-service:2.0.1-SNAPSHOT +-com.example.framework:example-spring-utils:0.5.9-SNAPSHOT +-org.slf4j:slf4j-api:1.7.12 (managed) < -- org.slf4j:slf4j-api:1.7.11
Here, your blah-service project wanted version 1.7.12 of artifact org.slf4j:slf4j-api, but blah-service’s dependency com.example.framework:example-spring-utils wanted version 1.7.11. That’s fine: the RequireUpperBoundDeps rule assumes backwards-compatibility (e.g., if a dependency requests version 1.7.11 of some artifact, it should be happy to get 1.7.12 instead).
Here’s another example showing a problem:
... and +-com.example.blah:blah-service:2.0.1-SNAPSHOT +-io.springfox:springfox-swagger2:2.5.0 +-io.springfox:springfox-swagger-common:2.5.0 +-org.slf4j:slf4j-api:1.7.12 (managed) < -- org.slf4j:slf4j-api:1.7.21 and ...
In this case, a transitive dependency called springfox-swagger-common wants slf4j-api version 1.7.21, but our project specifies version 1.7.12. In general, when an artifact says it wants version 1.7.21 of a dependency, giving it version 1.7.12 isn’t going to work so well, so the RequireUpperBoundDeps rule detects an error and stops the build.
How to fix it
To resolve the problem, your project either needs to back off to a previous version of the dependency that is requiring the too-high version of the transitive dependency, or your project needs to request the highest version of that dependency that any of its transitive dependencies want. Since the latter is the more common case, let’s look at the simple way to pursue that path:
Just scan down the right hand side of the maven enforcer plugin’s output for the artifact in question, looking for the highest version number. Then use that as your version in your own project’s pom file.
In our example here, the highest version of the slf4j-api artifact that showed in the maven enforcer plugin’s output for my project was 1.7.21. I updated that dependency in my project’s pom file with that version number and the maven enforcer plugin was satisfied.