Apakah ada cara untuk mengecualikan artefak yang diwarisi dari Badan POM induk?

119

Artefak dari dependensi dapat dikecualikan dengan mendeklarasikan sebuah <exclusions>elemen di dalam a. <dependency>Namun dalam hal ini diperlukan untuk mengecualikan artefak yang diwarisi dari project induk. Berikut kutipan dari Badan POM yang sedang dibahas:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>jruby</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
    </parent>

    <dependencies>      
        <dependency>
            <groupId>com.liferay.portal</groupId>
            <artifactId>ALL-DEPS</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</project>

baseartefak, bergantung pada javax.mail:mail-1.4.jar, dan ALL-DEPSbergantung pada versi lain dari pustaka yang sama. Karena fakta bahwa mail.jardari yang ALL-DEPSada di lingkungan eksekusi, meskipun tidak diekspor, bertabrakan dengan mail.jaryang ada di induk, yang dicakup sebagai compile.

Solusinya mungkin dengan menyingkirkan mail.jar dari POM induk, tetapi sebagian besar proyek yang mewarisi basis, membutuhkannya (seperti ketergantungan transtif untuk log4j). Jadi Yang ingin saya lakukan adalah mengecualikan pustaka induk dari proyek anak , karena ini bisa dilakukan jika basemerupakan ketergantungan dan bukan pom induk:

...
    <dependency>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
        <type>pom<type>
        <exclusions>
          <exclusion>
             <groupId>javax.mail</groupId>
             <artifactId>mail</artifactId>
          </exclusion>
        </exclusions>
    </dependency>
...
Miguel
sumber

Jawaban:

49

Beberapa ide:

  1. Mungkin Anda tidak bisa mewarisi dari induknya dalam kasus tersebut (dan menyatakan ketergantungan basedengan pengecualian). Tidak berguna jika Anda memiliki banyak barang di pom induk.

  2. Hal lain yang harus diuji adalah mendeklarasikan mailartefak dengan versi yang diperlukan oleh di ALL-DEPSbawah dependencyManagementdalam pom induk untuk memaksa konvergensi (meskipun saya tidak yakin ini akan menyelesaikan masalah pelingkupan).

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. Atau Anda dapat mengecualikan mailketergantungan dari log4j jika Anda tidak menggunakan fitur yang mengandalkannya (dan inilah yang akan saya lakukan):
<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.15</version>
  <scope>provided</scope>
  <exclusions>
    <exclusion>
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
    </exclusion>
    <exclusion>
      <groupId>javax.jms</groupId>
      <artifactId>jms</artifactId>
    </exclusion>
    <exclusion>
      <groupId>com.sun.jdmk</groupId>
      <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
      <groupId>com.sun.jmx</groupId>
      <artifactId>jmxri</artifactId>
    </exclusion>
  </exclusions>
</dependency>
  1. Atau Anda dapat kembali ke versi 1.2.14 dari log4j daripada versi 1.2.15 yang sesat (mengapa mereka tidak menandai dependensi di atas sebagai opsional ?!).
Pascal Thivent
sumber
Terima kasih untuk balasan Anda. Ini berisi banyak informasi berguna. Perihal 1) Seperti yang Anda ketahui tidak akan optimal karena parent pom tidak hanya berisi dependensi yang secara transitif akan terselesaikan jika base ditandai sebagai dependency, tetapi juga common reporting, source management, dan hal-hal lain yang digunakan kembali di antara setiap project di perusahaan. Sehubungan dengan 2) Saya mencobanya, tetapi juga menentukan cakupan artefak sebagaimana disediakan, dan berhasil :). Pada awalnya, saya berpikir bahwa kompilasi lebih diutamakan daripada yang disediakan, itu tidak akan berfungsi, tetapi untungnya saya salah (POM anak menggantikan konfigurasi orang tua)
Miguel
29

Anda dapat mengelompokkan dependensi Anda dalam proyek yang berbeda dengan kemasan pomseperti yang dijelaskan oleh Praktik Terbaik Sonatypes :

<project>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>base-dependencies</artifactId>
    <groupId>es.uniovi.innova</groupId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <dependencies>
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>1.4</version>
        </dependency>
    </dependencies>
</project>

dan mereferensikannya dari orang tua-pom Anda (perhatikan ketergantungannya <type>pom</type>):

<project>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>base</artifactId>
    <groupId>es.uniovi.innova</groupId>
    <version>1.0.0</version>
    <packaging>pom</packaging>
    <dependencies>
        <dependency>
            <artifactId>base-dependencies</artifactId>
            <groupId>es.uniovi.innova</groupId>
            <version>1.0.0</version>
            <type>pom</type>
        </dependency>
    </dependencies>
</project>

Proyek anak Anda mewarisi pom induk ini seperti sebelumnya. Tapi sekarang, ketergantungan email bisa dikecualikan di proyek-anak dalam dependencyManagementblok:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>test</groupId>
    <artifactId>jruby</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <artifactId>base-dependencies</artifactId>
                <groupId>es.uniovi.innova</groupId>
                <version>1.0.0</version>
                <exclusions>
                    <exclusion>
                        <groupId>javax.mail</groupId>
                        <artifactId>mail</artifactId>
                    </exclusion>
                </exclusions>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
timomeinen
sumber
4
+1 untuk ini, meskipun anak pom harus menggunakan bagian <dependencies> daripada <dependencyManagement> karena yang terakhir adalah untuk mengelola versi dependensi dari dalam induk pom.
Matthew Wise
1
Ini juga dikenal sebagai BOM, alias bill of material :-)
Pim Hazebroek
Apakah ini hanya berfungsi dengan dependensi transitif? Pom orang tua saya berisi log4j dan itu mencegah logback pom saya berfungsi dengan baik.
Sridhar Sarnobat
10

Jangan gunakan pom orang tua

Ini mungkin terdengar ekstrem, tetapi dengan cara yang sama "warisan neraka" adalah alasan beberapa orang berpaling dari Pemrograman Berorientasi Objek (atau lebih suka komposisi daripada warisan ), hapus <parent>blok bermasalah dan salin dan tempel apa pun yang <dependencies>Anda butuhkan (jika tim Anda memberi Anda kebebasan ini).

Asumsi bahwa pemisahan pom menjadi orang tua dan anak untuk "digunakan kembali" dan "menghindari redunansi" harus diabaikan dan Anda harus melayani kebutuhan mendesak Anda terlebih dahulu (penyembuhannya lebih buruk daripada penyakitnya). Selain itu, redundansi memiliki kelebihan - yaitu kemandirian terhadap perubahan eksternal (yaitu stabilitas).

Ini lebih mudah daripada kedengarannya jika Anda menghasilkan pom yang efektif (gerhana menyediakannya tetapi Anda dapat membuatnya dari baris perintah dengan mvn help:effective).

Contoh

Saya ingin menggunakan logbacksebagai pengikat slf4j saya, tetapi pom orang tua saya menyertakan log4jketergantungan. Saya tidak ingin pergi dan harus mendorong ketergantungan anak-anak lain pada log4j ke dalam pom.xmlfile mereka sendiri sehingga milik saya tidak terhalang.

Sridhar Sarnobat
sumber
1
Dokumentasikan ini (dan prosedur yang Anda ikuti) dengan sangat hati-hati karena pengelola selanjutnya perlu mengulanginya jika perlu menggunakan versi pom induk yang diperbarui.
Thorbjørn Ravn Andersen
Tentunya yang Anda maksud tidak menggunakan dependensi di pom induk? Parent pom masih sangat berguna untuk mengatur versi dependensi, dan plugin umum. Hanya menggunakannya untuk menyuntikkan dependensi dapat menjadi bumerang - kami menggunakannya hanya untuk dependensi yang harus dimiliki (seperti serangkaian permulaan boot musim semi yang penting untuk orang tua untuk layanan mikro)
Amit Goldstein
Tidak, saya tidak mengatakan menggunakan pom orang tua yang ringan. Orang lain di tim Anda tidak mengizinkan Anda untuk memangkas pom induk karena aplikasi lain bergantung pada sampah di pom induk yang tidak Anda inginkan.
Sridhar Sarnobat
8

Definisikan ulang ketergantungan (di pom anak) dengan scopesistem yang mengarah ke toples kosong:

<dependency>
    <groupId>dependency.coming</groupId>
    <artifactId>from.parent</artifactId>
    <version>0</version>
    <scope>system</scope>
    <systemPath>${project.basedir}/empty.jar</systemPath>
</dependency>

Stoples hanya dapat berisi satu file kosong:

touch empty.txt
jar cvf empty.txt
Bax
sumber
Terima kasih atas jawaban Anda, pada Windows 10 aku harus lari notepad empty.classkemudian jar cvf empty.jar empty.classuntuk menghasilkan jar kosong.
Rov
1
Sepertinya praktik yang buruk
Piotr Żak
6

Sudahkah Anda mencoba secara eksplisit menyatakan versi mail.jar yang Anda inginkan? Resolusi ketergantungan Maven harus menggunakan ini untuk resolusi ketergantungan pada semua versi lainnya.

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>test</groupId>
  <artifactId>jruby</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <artifactId>base</artifactId>
        <groupId>es.uniovi.innova</groupId>
        <version>1.0.0</version>
    </parent>
    <dependencies>          
        <dependency>
            <groupId>javax.mail</groupId>
            <artifactId>mail</artifactId>
            <version>VERSION-#</version>
            <scope>provided</scope>
        </dependency> 
        <dependency>
            <groupId>com.liferay.portal</groupId>
            <artifactId>ALL-DEPS</artifactId>
            <version>1.0</version>
            <scope>provided</scope>
            <type>pom</type>
        </dependency>
    </dependencies>
</project>
kedai bir 91
sumber
1
Pendekatan Anda, karena solusi Pascal # 2 juga valid, pada kenyataannya, Anda juga memperhitungkan bahwa ketergantungan mail harus dideklarasikan sebagai disediakan. Terima kasih.
Miguel
Cakupan yang diberikan tidak berhasil untuk saya. Saya menggunakan tes lingkup, silakan periksa jawaban saya. stackoverflow.com/a/55970293/4587961
Yan Khonski
3

Taruhan terbaik adalah membuat dependensi yang tidak selalu ingin Anda warisi secara intransitif.

Anda dapat melakukan ini dengan menandainya di pom induk dengan cakupan yang disediakan.

Jika Anda masih ingin orang tua mengelola versi deps ini, Anda dapat menggunakan <dependencyManagement>tag untuk menyiapkan versi yang Anda inginkan tanpa mewarisi secara eksplisit, atau meneruskan pewarisan tersebut ke turunannya.

Ajax
sumber
1

Ketika Anda memanggil sebuah paket tetapi tidak menginginkan beberapa dependensinya, Anda dapat melakukan hal seperti ini (dalam hal ini saya tidak ingin log4j lama ditambahkan karena saya perlu menggunakan yang lebih baru):

<dependency>
  <groupId>package</groupId>
  <artifactId>package-pk</artifactId>
  <version>${package-pk.version}</version>

  <exclusions>
    <exclusion>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-core</artifactId>
    </exclusion>
    <exclusion>
      <groupId>org.apache.logging.log4j</groupId>
      <artifactId>log4j-api</artifactId>
    </exclusion>
  </exclusions>
</dependency>

<!-- LOG4J -->
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-core</artifactId>
  <version>2.5</version>
</dependency>
<dependency>
  <groupId>org.apache.logging.log4j</groupId>
  <artifactId>log4j-api</artifactId>
  <version>2.5</version>
</dependency>

Ini bekerja untuk saya ... tapi saya cukup baru mengenal java / maven jadi mungkin belum optimal.

bastienb1991
sumber
Selamat datang di Stack Overflow, dan jangan biarkan orang-orang kasar yang selalu saya abaikan pertanyaan saya membuat Anda enggan memposting.
Sridhar Sarnobat
1

Aku benar-benar perlu melakukan hal kotor ini ... Begini caranya

Saya mendefinisikan ulang dependensi tersebut dengan cakupan test. Scope providedtidak berhasil untuk saya.

Kami menggunakan plugin Spring Boot untuk membuat botol gemuk. Kami memiliki modul umum yang mendefinisikan pustaka umum, misalnya Springfox swagger-2. Layanan super saya harus memiliki kesamaan orang tua (tidak ingin melakukannya, tetapi aturan perusahaan memaksa!)

Jadi orang tua atau milik saya punya pom.

<dependencyManagement>

    <!- I do not need Springfox in one child but in others ->

    <dependencies>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>${swagger.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>com.google.guava</groupId>
                    <artifactId>guava</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>${swagger.version}</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-bean-validators</artifactId>
            <version>${swagger.version}</version>
        </dependency>

       <!- All services need them ->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>${apache.poi.version}</version>
        </dependency>
    </dependencies>
</dependencyManagement>

Dan pom layanan super saya .

<name>super-service</name>
<parent>
    <groupId>com.company</groupId>
    <artifactId>common</artifactId>
    <version>1</version>
</parent>

<dependencies>

    <!- I don't need them ->

    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-swagger2</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-bean-validators</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.springfox</groupId>
        <artifactId>springfox-core</artifactId>
        <version>2.8.0</version>
        <scope>test</scope>
    </dependency>

    <!- Required dependencies ->

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
     <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.poi</groupId>
        <artifactId>poi-ooxml</artifactId>
    </dependency>
</dependencies>

Ini adalah ukuran artefak lemak terakhir

82.3 MB (86,351,753 bytes) - redefined dependency with scope test
86.1 MB (90,335,466 bytes) - redefined dependency with scope provided
86.1 MB (90,335,489 bytes) - without exclusion

Juga jawaban ini layak untuk disebutkan - Saya ingin melakukannya, tetapi saya malas ... https://stackoverflow.com/a/48103554/4587961

Yan Khonski
sumber
0

Kita dapat menambahkan pom induk sebagai dependensi dengan tipe pom dan membuat pengecualian untuk itu. Karena bagaimanapun pom induk diunduh. Ini berhasil untuk saya

<dependency>
  <groupId>com.abc.boot</groupId>
  <artifactId>abc-boot-starter-parent</artifactId>
  <version>2.1.5.RELEASE</version>
  <type>pom</type>
  <exclusions>
    <exclusion>
      <groupId>com.google.code.gson</groupId>
      <artifactId>gson</artifactId>
    </exclusion>
  </exclusions>   
</dependency>
Viki Jain
sumber