As you all know, we can’t have two classes with the same package and name in one project. So there would be conflicts if different versions of a package are imported. Obviously, in this case, only one version of Guava will be imported.
How to find dependency conflicts?
I’d like to introduce 2 useful tools to you. The first one is ‘maven-dependency-plugin’. It’s a Maven plugin, so you can use it directly. The command is listed below:
The result tells us that 2 dependencies imported the guava package, but only version 30 is available in this project. Version 29 is omitted.
Another tool is an IntelliJ IDEA plugin, called Maven Helper. It’s more convenient if you are using this development editor. You can see the conflicts directly in its panel.
How Maven chooses the version of dependency?
Actually, the rule is quite simple. You just need to remember 2 rules.
The first one is: nearest definition wins
“nearest definition” means that the version used will be the closest one to your project in the tree of dependencies.
1 2 3 4 5 6 7
POM |-- A | `-- B 1.0 |-- C `-- D `-- B 2.0
From this dependency tree, we can get 2 dependency paths: root-A-B1.0 and root-C-D-B2.0. You can see the first path is shorter than the second one, so according to this rule, version 1.0 will be chosen by Maven.
If two dependency versions are at the same depth, then you’ll need the second rule: first declaration wins. It means which dependency imported earlier will be chosen.
1 2 3 4 5 6
POM |-- A | `-- B 1.0 |-- C `-- B 2.0
Version 1.0 is imported earlier, so it will be the final winner.
Do you remember the example I mentioned before? The project imported 2 dependencies, study-maven-2 and study-maven-3. Both of these 2 libraries imported Guava directly.
Let’s have a look at the dependency tree of the project. You can see that version 30 is available, and another version of Guava is omitted. Because version 30 is imported firstly.
But there is an exceptional situation, it’s not a usual case; it happens when you importing the same library with a different version in one POM file. Then the latter one will win.
The first way to achieve this goal is that excluding the version you don’t want when importing the dependency. You need to add some exclusion configurations with the dependency importing. You can do it manually or with the Maven Helper plugin.
The second way is importing the version you want directly in your project, according to the rule we mentioned before, the directly imported version will be the available one. Let’s check the dependency tree again, now version 29 is the winner.
[INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ study-maven --- [INFO] org.example:study-maven:jar:1.0-SNAPSHOT [INFO] +- org.example:study-maven-2:jar:1.0-SNAPSHOT:compile [INFO] | \\- com.google.guava:guava:jar:29.0-jre:compile (version managed from 30.1.1-jre) [INFO] \\- org.example:study-maven-3:jar:1.0-SNAPSHOT:compile [INFO] \\- (com.google.guava:guava:jar:29.0-jre:compile - version managed from 30.1.1-jre; omitted for duplicate)
You can see, now version 29 is the winner.
Please attention that the dependency management’s priority is lower than the directly imported one. It means the dependency management can not change the version you imported directly.
What if we have to keep two versions?
Some libraries only work with the old version of Guava, but some of them only work with the new version.
Let’s say study-maven-2 only works with Guava 30.1, but study-maven-3 can not work without Guava 29. Here are the steps:
Create a new project;
Relocate all classes in package ‘com.google.common’ by maven-shade-plugin;
Import the shaded one.
Here what we need is the ‘maven-shade-plugin’. This plugin can relocate some classes, by changing its package name.
Here is an example, we’d like to relocate all classes in package ‘com.google.common’ to another package.
Your code will use the relocated classes after being compiled.
Before relocation, your code was importing the class of Guava from the original package; After relocation, your code is importing the same class from a new package.