Jeśli nie określimy żadnej wersji dla zależności tranzytywnych, to Maven spróbuje sam wybrać odpowiednią wersję. I ogólna zasada to – wygrywa zależność będąca najbliżej. Czyli będą najbliżej w pionie jak i w poziomie.
Zakładając następującą strukturę projektu
Załóżmy dla potrzeb następnych akapitów następującą strukturę projektu:
D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)
Gdzie D1,D2… są to po prostu zależności. A zależność, którą Maven będzie próbował rozwiązać to DT (w nawiasach podane są wersje). Strzałki (->) oznaczają po prostu zależność w tym samym kierunku co ich groty (od artefaktu po lewej do artefaktu po prawej).
Najbliżej w pionie
Jeśli chodzi o sytuację kolejności w pionie to sprawa jest prosta – wygrywa ta, która jest zdefiniowana jako pierwsza (patrząc od góry do dołu). Czyli w naszym projekcie, gdyby Maven brał pod uwagę tylko i wyłącznie zasadę „Najbliżej w pionie”, to wygrała by wersja version 1:
D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)
Najbliżej w poziomie
Jeśli zaś chodzi o najbliższą zależność w poziomie, to wygrywa ta zależność, która będzie miała najkrótszy ciąg zależności. Jeśli Maven brałby pod uwagę tylko zasadę „Najbliżej w poziomie” to byśmy mieli trzech kandydatów:
D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)
Najbliżej w pionie i najbliżej poziomie
Biorąc pod uwagę obydwie zasady – „Najbliżej w pionie” i „Najbliżej w poziomie”, Maven wybierze zależność z wersją version 2:
D1 -> D12 -> DT(version 1)
D2 -> DT(version 2)
D3 -> DT(version 3)
D4 -> DT(version 2)
I to jest zasada, którą kieruje się Maven przy rozwiązywaniu konfliktów.
Maven dependency tree
Aby zobaczyć jak Maven rozwiązuje tranzytywne konflikty wersji, można użyć wtyczki dependency z komendą tree i parametrem verbose:
mvn dependency:tree -DverboseDla zbliżonej struktury jak w założeniach (patrz pierwszy nagłówek), Maven zwraca następujące drzewo zależności:
[INFO] pl.damianradowiecki:TEST:jar:1.0-SNAPSHOT
[INFO] +- pl.damianradowiecki:D1:pom:1:compile
[INFO] | \- pl.damianradowiecki:D12:pom:1:compile
[INFO] | \- (pl.damianradowiecki:DT:jar:1:compile - omitted for conflict with 2)
[INFO] +- pl.damianradowiecki:D2:pom:1:compile
[INFO] | \- pl.damianradowiecki:DT:jar:2:compile
[INFO] +- pl.damianradowiecki:D3:pom:1:compile
[INFO] | \- (pl.damianradowiecki:DT:jar:3:compile - omitted for conflict with 2)
[INFO] \- pl.damianradowiecki:D4:pom:1:compile
[INFO] \- (pl.damianradowiecki:DT:jar:2:compile - omitted for duplicate)Jak można zauważyć, niektóre zależności są oznaczane jako omitted for conflict a inne jako omitted for duplicate.
omitted for conflict
Maven w drzewie zależności oznacza zależności jako omitted for conflict, te zależności które przegrały w „wyścigu” (najbliżej w pionie i najbliżej w poziomie) i mają różną wersję od tej wybranej.
omitted for duplicate
Maven w drzewie zależności oznacza zależności jako omitted for duplicate, te zależności które przegrały w „wyścigu” (najbliżej w pionie i najbliżej w poziomie) i mają tę samą wersję co wybrana.
Warto zajrzeć
1. Projekt odzwierciedlający przykład z wpisu (w celu uruchomienia podążaj za instrukcjami w pliku VersionTest.java)
2. https://maven.apache.org/plugins-archives/maven-dependency-plugin-2.8/examples/resolving-conflicts-using-the-dependency-tree.html
3. https://reflectoring.io/maven-bom/
