Cara Mengatasi Tabrakan Versi Artefak di Maven

1. Ikhtisar

Proyek multi-modul Maven dapat memiliki grafik ketergantungan yang kompleks. Ini dapat memiliki hasil yang tidak biasa, semakin banyak modul yang diimpor dari satu sama lain.

Dalam tutorial ini, kita akan melihat bagaimana menyelesaikan tabrakan versi artefak di Maven .

Kami akan mulai dengan proyek multi-modul di mana kami sengaja menggunakan versi berbeda dari artefak yang sama. Kemudian, kita akan melihat cara mencegah mendapatkan versi artefak yang salah dengan manajemen pengecualian atau ketergantungan.

Terakhir, kami akan mencoba menggunakan plugin m aven-penegak untuk mempermudah kontrol, dengan melarang penggunaan dependensi transitif.

2. Tabrakan Versi Artefak

Setiap ketergantungan yang kami sertakan dalam proyek kami mungkin ditautkan ke artefak lain. Maven dapat secara otomatis membawa artefak ini, juga disebut dependensi transitif. Tabrakan versi terjadi saat beberapa dependensi ditautkan ke artefak yang sama, tetapi menggunakan versi yang berbeda.

Akibatnya, mungkin ada kesalahan dalam aplikasi kita baik dalam fase kompilasi maupun saat runtime .

2.1. Struktur Proyek

Mari kita tentukan struktur proyek multi-modul untuk bereksperimen. Proyek kami terdiri dari modul induk tabrakan versi dan tiga anak:

version-collision project-a project-b project-collision 

The pom.xml untuk proyek-a dan proyek-b hampir identik. Satu-satunya perbedaan adalah versi artefak com.google.guava yang mereka andalkan. Secara khusus, project-a menggunakan versi 22.0 :

  com.google.guava guava 22.0  

Tapi, project-b menggunakan versi yang lebih baru, 29.0-jre :

  com.google.guava guava 29.0-jre  

Modul ketiga, tabrakan proyek , bergantung pada dua modul lainnya:

  com.baeldung project-a 0.0.1-SNAPSHOT   com.baeldung project-b 0.0.1-SNAPSHOT  

Jadi, versi jambu biji mana yang akan tersedia untuk tabrakan proyek ?

2.2. Menggunakan Fitur dari Versi Ketergantungan Khusus

Kita bisa mengetahui ketergantungan mana yang digunakan dengan membuat tes sederhana di modul tabrakan proyek yang menggunakan metode Futures.immediateVoidFuture dari guava :

@Test public void whenVersionCollisionDoesNotExist_thenShouldCompile() { assertThat(Futures.immediateVoidFuture(), notNullValue()); }

Metode ini hanya tersedia dari versi 29.0-jre . Kami telah mewarisi ini dari salah satu modul lain, tetapi kami hanya dapat mengompilasi kode kami jika kami mendapatkan ketergantungan transitif dari project-b.

2.3. Kesalahan Kompilasi yang Disebabkan oleh Benturan Versi

Bergantung pada urutan dependensi dalam modul tabrakan proyek , dalam kombinasi tertentu Maven mengembalikan kesalahan kompilasi:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:testCompile (default-testCompile) on project project-collision: Compilation failure [ERROR] /tutorials/maven-all/version-collision/project-collision/src/test/java/com/baeldung/version/collision/VersionCollisionUnitTest.java:[12,27] cannot find symbol [ERROR] symbol: method immediateVoidFuture() [ERROR] location: class com.google.common.util.concurrent.Futures

Itu adalah hasil dari benturan versi artefak com.google.guava . Secara default, untuk dependensi di level yang sama dalam pohon dependensi, Maven memilih library pertama yang ditemukannya. Dalam kasus kami, kedua dependensi com.google.guava memiliki tinggi yang sama dan versi yang lebih lama dipilih.

2.4. Menggunakan maven-dependency-plugin

The maven-ketergantungan-plugin adalah alat yang sangat membantu untuk menyajikan semua dependensi dan versi mereka:

% mvn dependency:tree -Dverbose [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-collision --- [INFO] com.baeldung:project-collision:jar:0.0.1-SNAPSHOT [INFO] +- com.baeldung:project-a:jar:0.0.1-SNAPSHOT:compile [INFO] | \- com.google.guava:guava:jar:22.0:compile [INFO] \- com.baeldung:project-b:jar:0.0.1-SNAPSHOT:compile [INFO] \- (com.google.guava:guava:jar:29.0-jre:compile - omitted for conflict with 22.0)

The -Dverbose menampilkan bendera bertentangan artefak. Faktanya, kami memiliki ketergantungan com.google.guava dalam dua versi: 22.0 dan 29.0-jre. Yang terakhir adalah yang ingin kami gunakan dalam modul tabrakan proyek .

3. Mengecualikan Ketergantungan Transitif Dari Artefak

Salah satu cara untuk mengatasi benturan versi adalah dengan menghapus ketergantungan transitif yang bertentangan dari artefak tertentu . Dalam contoh kami, kami tidak ingin library com.google.guava ditambahkan secara transit dari artefak project-a .

Oleh karena itu, kami dapat mengecualikannya di project-collision pom:

  com.baeldung project-a 0.0.1-SNAPSHOT   com.google.guava guava     com.baeldung project-b 0.0.1-SNAPSHOT  

Sekarang, ketika kita menjalankan perintah dependency: tree , kita dapat melihat bahwa perintah tersebut sudah tidak ada lagi:

% mvn dependency:tree -Dverbose [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-collision --- [INFO] com.baeldung:project-collision:jar:0.0.1-SNAPSHOT [INFO] \- com.baeldung:project-b:jar:0.0.1-SNAPSHOT:compile [INFO] \- com.google.guava:guava:jar:29.0-jre:compile

Hasilnya, fase kompilasi berakhir tanpa kesalahan dan kita dapat menggunakan kelas dan metode dari versi 29.0-jre .

4. Menggunakan Bagian dependencyManagement

Bagian dependencyManagement Maven adalah mekanisme untuk memusatkan informasi dependensi . Salah satu fiturnya yang paling berguna adalah untuk mengontrol versi artefak yang digunakan sebagai dependensi transitif.

Dengan pemikiran tersebut, mari buat konfigurasi dependencyManagement di pom induk kita :

   com.google.guava guava 29.0-jre   

Akibatnya, Maven akan pastikan untuk menggunakan versi 29.0-jre dari com.google.guava artefak di semua modul anak:

% mvn dependency:tree -Dverbose [INFO] --- maven-dependency-plugin:2.8:tree (default-cli) @ project-collision --- [INFO] com.baeldung:project-collision:jar:0.0.1-SNAPSHOT [INFO] +- com.baeldung:project-a:jar:0.0.1-SNAPSHOT:compile [INFO] | \- com.google.guava:guava:jar:29.0-jre:compile (version managed from 22.0) [INFO] \- com.baeldung:project-b:jar:0.0.1-SNAPSHOT:compile [INFO] \- (com.google.guava:guava:jar:29.0-jre:compile - version managed from 22.0; omitted for duplicate)

5. Mencegah Ketergantungan Transitif yang Tidak Disengaja

The maven-enforcer-plugin provides many built-in rules that simplify the management of a multi-module project. One of them bans the use of classes and methods from transitive dependencies.

Explicit dependency declaration removes the possibility of version collision of artifacts. Let's add the maven-enforcer-plugin with that rule to our parent pom:

 org.apache.maven.plugins maven-enforcer-plugin 3.0.0-M3   enforce-banned-dependencies  enforce         

As a consequence, we must now explicitly declare the com.google.guava artifact in our project-collision module if we want to use it ourselves. We must either specify the version to use, or set up dependencyManagement in the parent pom.xml. This makes our project more mistake proof, but requires us to be more explicit in our pom.xml files.

6. Conclusion

In this article, we've seen how to resolve a version collision of artifacts in Maven.

First, we explored an example of a version collision in a multi-module project.

Kemudian, kami menunjukkan cara mengecualikan dependensi transitif di pom.xml . Kami melihat cara mengontrol versi dependensi dengan bagian dependencyManagement di pom.xml induk .

Terakhir, kami mencoba maven-penegak-plugin untuk melarang penggunaan dependensi transitif untuk memaksa setiap modul mengambil kendali sendiri.

Seperti biasa, kode yang ditampilkan dalam artikel ini tersedia di GitHub.