Maven: cara mengganti dependensi yang ditambahkan oleh perpustakaan

116

Inilah masalah umum saya:

Proyek saya P bergantung pada A yang bergantung pada B yang bergantung pada C yang bergantung pada versi 1.0.1 dari D.

Ada masalah dengan versi 1.0.1 dari D dan saya ingin memaksa penggunaan modul lain. Saya tidak tahu cara mendeklarasikan ini di POM proyek saya karena saya belum menambahkan ketergantungan pada D secara langsung. C yang menyatakan ketergantungan pada D.

Penting: Dalam hal ini, tidak hanya versinya yang diubah, tetapi grup & artefaknya juga. Jadi, ini bukan hanya masalah menimpa versi dependensi, melainkan mengecualikan modul dan menyertakan modul lainnya.

Dalam kasus konkret, D adalah StAX yang 1.0.1 memiliki bug . Menurut catatan di bug, "masalah diselesaikan dengan mengganti stax-api-1.0.1 (maven GroupId = stax) oleh stax-api-1.0-2 (maven GroupId = javax.xml.stream)" jadi saya sedang mencoba itu.

Jadi, D = stax: stax-api: jar: 1.0.1 dan C = org.apache.xmlbeans: xmlbeans: jar: 2.3.0

Saya menggunakan maven 2.0.9 jika itu penting.

Keluaran ketergantungan mvn: pohon "

mvn dependency:tree
[..snip..]
[INFO] +- org.apache.poi:poi-ooxml:jar:3.6:compile
[INFO] |  +- org.apache.poi:poi-ooxml-schemas:jar:3.6:compile
[INFO] |  |  +- org.apache.xmlbeans:xmlbeans:jar:2.3.0:compile
[INFO] |  |  |  \- stax:stax-api:jar:1.0.1:compile

Di POM proyek saya, saya memiliki ketergantungan berikut pada "A":

<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.6</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.6</version>
</dependency>

Terima kasih sebelumnya.

wishihadabettername
sumber

Jawaban:

100

Cukup tentukan versi di pom Anda saat ini. Versi yang ditentukan di sini akan menimpa versi lainnya.

Memaksakan versi versi
A akan selalu dihormati jika dideklarasikan dalam POM saat ini dengan versi tertentu - namun, perlu dicatat bahwa ini juga akan memengaruhi pom lain di hilir jika versi itu sendiri bergantung pada penggunaan dependensi transitif.


Sumber:

Colin Hebert
sumber
5
tidak jelas bagaimana saya dapat menentukan versi karena saya tidak menyatakan ketergantungan pada D. Selain itu, tautan pertama yang Anda berikan memiliki "Dokumen ini menjelaskan persyaratan lainnya untuk manajemen ketergantungan yang BELUM diterapkan untuk Maven 2.0, terutama yang berkaitan dengan dependensi transitif. " di atas.
wishihadabettername
@wishihadabettername, Seperti yang dikatakan dalam dokumen lain: "Anda dapat secara eksplisit menambahkan ketergantungan ke D 2.0 di A untuk memaksa penggunaan D 2.0"
Colin Hebert
1
Anda sebenarnya menduplikasi entri <dependency> yang sama di pom Anda sendiri. Dalam ketergantungan Anda, tentukan <version> yang Anda inginkan. Itu akan menimpa versi apa pun yang digunakan oleh dependensi "lebih dalam".
Keith Tyler
27

Alternatifnya, Anda bisa mengecualikan dependensi yang tidak Anda inginkan. STAX disertakan dalam JDK 1.6, jadi jika Anda menggunakan 1.6 Anda bisa mengecualikannya sepenuhnya.

Contoh saya di bawah ini sedikit salah untuk Anda - Anda hanya memerlukan satu dari dua pengecualian tetapi saya tidak yakin yang mana. Ada versi lain dari Stax yang mengambang, dalam contoh saya di bawah ini saya mengimpor A yang mengimpor B yang mengimpor C & D yang masing-masing (melalui lebih banyak ketergantungan transitif) mengimpor versi Stax yang berbeda. Jadi dalam ketergantungan saya pada 'A', saya mengecualikan kedua versi Stax.

<dependency>
  <groupId>a.group</groupId>
  <artifactId>a.artifact</artifactId>
  <version>a.version</version>
  <exclusions>
    <!--  STAX comes with Java 1.6 -->
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>javax.xml.stream</groupId>
    </exclusion>
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>stax</groupId>
    </exclusion>
  </exclusions>
<dependency>
scot
sumber
1
Perlu diperhatikan bahwa ketergantungan transitif ini dapat digunakan dan pengecualian dapat menyebabkan kegagalan build jika diperlukan.
Bernhard Colby
Jika Anda menggunakan JDK modern (yaitu 1.6+) dan Anda memerlukan versi stax yang jauh lebih lama yang disertakan melalui ketergantungan transitif, Anda mungkin akan mengalami segala macam masalah loader kelas runtime yang mengerikan. Saran saya: gunakan yang ada di JDK. Jika Anda mendapatkan "kegagalan build", Anda mengandalkan API kuno dengan beberapa bentuk yang harus diupgrade. Atau: kembalikan JDK Anda ke 1.5. Semoga beruntung dengan itu.
scot
11

Apa yang Anda masukkan ke dalam </dependencies>tag root pom akan disertakan oleh semua modul turunan dari root pom. Jika semua modul Anda menggunakan dependensi itu, inilah caranya.

Namun, jika hanya 3 dari 10 modul anak Anda menggunakan beberapa ketergantungan, Anda tidak ingin ketergantungan ini disertakan dalam semua modul anak Anda. Dalam hal ini, Anda bisa meletakkan dependensi di dalam </dependencyManagement>. Ini akan memastikan bahwa setiap modul anak yang membutuhkan ketergantungan harus mendeklarasikannya dalam file pom mereka sendiri, tetapi mereka akan menggunakan versi yang sama dari ketergantungan tersebut seperti yang ditentukan dalam </dependencyManagement>tag Anda .

Anda juga dapat menggunakan </dependencyManagement>untuk mengubah versi yang digunakan dalam dependensi transitif, karena versi yang dideklarasikan di file pom paling atas adalah versi yang akan digunakan. Ini dapat berguna jika proyek A Anda menyertakan proyek eksternal B v1.0 yang menyertakan proyek eksternal C v1.0 lainnya. Kadang-kadang terjadi pelanggaran keamanan ditemukan di proyek C v1.0 yang diperbaiki di v1.1, tetapi pengembang B lambat memperbarui proyek mereka untuk menggunakan v1.1 dari C. Dalam hal ini, Anda dapat dengan mudah menyatakan ketergantungan pada C v1.1 di root pom proyek Anda di dalam `, dan semuanya akan baik-baik saja (dengan asumsi bahwa B v1.0 masih dapat dikompilasi dengan C v1.1).

Kent Munthe Caspersen
sumber
10

Saya juga mengalami masalah saat membatalkan ketergantungan di perpustakaan pihak ketiga. Saya menggunakan pendekatan scot dengan pengecualian tetapi saya juga menambahkan ketergantungan dengan versi yang lebih baru di pom. (Saya menggunakan Maven 3.3.3)

Jadi untuk contoh stAX akan terlihat seperti ini:

<dependency>
  <groupId>a.group</groupId>
  <artifactId>a.artifact</artifactId>
  <version>a.version</version>
  <exclusions>
    <!--  STAX comes with Java 1.6 -->
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>javax.xml.stream</groupId>
    </exclusion>
    <exclusion>
      <artifactId>stax-api</artifactId>
      <groupId>stax</groupId>
    </exclusion>
  </exclusions>
<dependency>

<dependency>
    <groupId>javax.xml.stream</groupId>
    <artifactId>stax-api</artifactId>
    <version>1.0-2</version>
</dependency>
Patrick Koorevaar
sumber
1

Jawaban yang diterima benar, tetapi saya ingin menambahkan dua sen saya. Saya mengalami masalah ketika saya memiliki proyek A yang memiliki proyek B sebagai ketergantungan. Kedua proyek menggunakan slf4j tetapi proyek B menggunakan log4j sedangkan proyek A menggunakan logback. Proyek B menggunakan slf4j 1.6.1, sedangkan proyek A menggunakan slf4j 1.7.5 (karena ketergantungan logback 1.2.3 yang sudah disertakan).

Masalahnya: Proyek A tidak dapat menemukan fungsi yang ada di slf4j 1.7.5, setelah memeriksa tab hierarki ketergantungan eclipe saya menemukan bahwa selama pembuatan itu menggunakan slf4j 1.6.1 dari proyek B, daripada menggunakan logback's slf4j 1.7.5 .

Saya memecahkan masalah ini dengan mengubah urutan ketergantungan pada proyek A pom, ketika saya memindahkan entri proyek B di bawah entri logback, kemudian maven mulai membangun proyek menggunakan slf4j 1.7.5.

Edit: Menambahkan dependensi slf4j 1.7.5 sebelum dependensi Project B juga berfungsi.

Fernando Maia
sumber