Gibt es überhaupt Möglichkeiten, Artefakte auszuschließen, die von einem übergeordneten POM geerbt wurden?

119

Artefakte aus Abhängigkeiten können ausgeschlossen werden, indem ein <exclusions>Element in a deklariert wird. <dependency>In diesem Fall muss jedoch ein von einem übergeordneten Projekt geerbtes Artefakt ausgeschlossen werden. Ein Auszug des zur Diskussion stehenden POM folgt:

<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>

baseArtefakt, hängt von einer anderen Version derselben Bibliothek ab javax.mail:mail-1.4.jarund ALL-DEPShängt von dieser ab. Aufgrund der Tatsache, dass mail.jarfrom ALL-DEPSin der Ausführungsumgebung vorhanden ist, obwohl es nicht exportiert wird, kollidiert es mit dem mail.jar, das auf dem übergeordneten Element vorhanden ist, für das der Gültigkeitsbereich gilt compile.

Eine Lösung könnte darin bestehen, mail.jar vom übergeordneten POM zu entfernen, aber die meisten Projekte, die base erben, benötigen es (wie es eine transtive Abhängigkeit für log4j ist). Ich möchte also einfach die Bibliothek der Eltern aus dem untergeordneten Projekt ausschließen , wie dies möglich wäre, wenn basees sich um eine Abhängigkeit und nicht um die übergeordnete POM handelt:

...
    <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
quelle

Antworten:

49

Einige Ideen:

  1. Vielleicht könnten Sie in diesem Fall einfach nicht vom Elternteil erben (und eine Abhängigkeit basemit dem Ausschluss deklarieren ). Nicht praktisch, wenn Sie viel Zeug im Eltern-Pom haben.

  2. Eine andere zu testende Sache wäre, das mailArtefakt mit der Version zu deklarieren, die von ALL-DEPSunter dependencyManagementim übergeordneten POM benötigt wird, um die Konvergenz zu erzwingen (obwohl ich nicht sicher bin, ob dies das Scoping-Problem lösen wird).

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. Oder Sie können die mailAbhängigkeit von log4j ausschließen, wenn Sie die darauf basierenden Funktionen nicht verwenden (und das würde ich tun):
<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. Oder Sie könnten auf die Version 1.2.14 von log4j anstelle der ketzerischen Version 1.2.15 zurückgreifen (warum haben sie die oben genannten Abhängigkeiten nicht als optional markiert ?!).
Pascal Thivent
quelle
Danke für deine Antwort. Es enthält viele nützliche Informationen. Zu 1) Wie Sie bemerkt haben, ist dies nicht optimal, da das übergeordnete POM nicht nur Abhängigkeiten enthält, die transitiv aufgelöst werden, wenn die Basis als Abhängigkeit markiert wurde, sondern auch allgemeine Berichte, Quellenverwaltung und andere Dinge, die in jedem Projekt im Unternehmen wiederverwendet werden. In Bezug auf 2) habe ich es versucht, aber auch den Umfang des Artefakts wie angegeben angegeben, und es hat funktioniert :). Zuerst dachte ich, dass das Kompilieren Vorrang vor dem Bereitgestellten hat, aber es funktioniert nicht, aber zum Glück habe ich mich geirrt (untergeordnetes POM überschreibt die Konfiguration des Elternteils)
Miguel
29

Sie können Ihre Abhängigkeiten innerhalb eines anderen Projekts mit einer Verpackung pomgruppieren, wie in den Best Practices von Sonatypes beschrieben :

<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>

und referenziere sie von deinem Eltern-Pom (beachte die Abhängigkeit <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>

Ihr Kind-Projekt erbt dieses Eltern-Pom wie zuvor. Jetzt kann die Mail-Abhängigkeit im untergeordneten Projekt innerhalb des dependencyManagementBlocks ausgeschlossen werden:

<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
quelle
4
+1 hierfür, obwohl das untergeordnete POM den Abschnitt <dependencies> anstelle von <dependencyManagement> verwenden sollte, da letzteres zum Verwalten der Versionen von Abhängigkeiten innerhalb eines übergeordneten Pom dient.
Matthew Wise
1
Dies ist auch als Stückliste bekannt, auch bekannt als Stückliste :-)
Pim Hazebroek
Funktioniert dies nur bei transitiven Abhängigkeiten? Mein übergeordneter Pom enthält log4j und verhindert, dass der Logback meines Poms ordnungsgemäß funktioniert.
Sridhar Sarnobat
10

Verwenden Sie keinen Eltern-Pom

Das mag extrem klingen, aber auf die gleiche Weise ist "Vererbungshölle" ein Grund, warum manche Leute der objektorientierten Programmierung den Rücken kehren (oder die Komposition der Vererbung vorziehen ), den problematischen <parent>Block entfernen und alles kopieren und einfügen, was <dependencies>Sie brauchen (wenn Ihr Team es Ihnen gibt diese Freiheit).

Die Annahme, dass die Aufteilung von Poms in Eltern und Kind zur "Wiederverwendung" und "Vermeidung von Redunanz" ignoriert werden sollte und Sie zuerst Ihre unmittelbaren Bedürfnisse befriedigen sollten (die Heilung ist schlimmer als die Krankheit). Außerdem hat Redundanz ihre Vorteile - nämlich die Unabhängigkeit von externen Änderungen (dh Stabilität).

Dies ist einfacher als es sich anhört, wenn Sie den effektiven POM generieren (Eclipse bietet ihn an, aber Sie können ihn über die Befehlszeile mit generieren mvn help:effective).

Beispiel

Ich möchte logbackals slf4j-Bindung verwenden, aber mein übergeordnetes pom enthält die log4jAbhängigkeit. Ich möchte nicht gehen und die Abhängigkeit der anderen Kinder von log4j in ihre eigenen pom.xmlDateien verschieben müssen, damit meine nicht behindert werden.

Sridhar Sarnobat
quelle
1
Dokumentieren Sie dies (und das von Ihnen befolgte Verfahren) sehr sorgfältig, da die zukünftigen Betreuer dies wiederholen müssen, wenn sie eine aktualisierte Version des übergeordneten POM verwenden müssen.
Thorbjørn Ravn Andersen
Sicherlich meinst du, keine Abhängigkeiten im übergeordneten POM verwenden? Parent Pom ist immer noch sehr nützlich, um Abhängigkeitsversionen und gängige Plugins zu verwalten. Nur die Verwendung, um Abhängigkeiten zu injizieren, kann nach hinten losgehen - wir verwenden sie nur für die Must-Have-Abhängigkeiten (wie eine Reihe wichtiger Starter für einen Boot für einen Elternteil für Microservices)
Amit Goldstein
Nein, ich sage nicht, dass Sie einen leichten Eltern-Pom verwenden. Andere in Ihrem Team erlauben Ihnen nicht, den übergeordneten Pom zu kürzen, da andere Apps von dem Müll im übergeordneten Pom abhängen, den Sie nicht möchten.
Sridhar Sarnobat
8

Definieren Sie die Abhängigkeit (im untergeordneten POM) scopeneu, indem das System auf ein leeres Glas zeigt:

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

Das Glas kann nur eine einzige leere Datei enthalten:

touch empty.txt
jar cvf empty.txt
Bax
quelle
Vielen Dank für Ihre Antwort, auf Windows 10 musste ich laufe notepad empty.classdann jar cvf empty.jar empty.classein leeres Glas zu erzeugen.
Rov
1
Sieht nach schlechter Praxis aus
Piotr Żak
6

Haben Sie versucht, die gewünschte Version von mail.jar explizit zu deklarieren? Die Abhängigkeitsauflösung von Maven sollte dies für die Abhängigkeitsauflösung gegenüber allen anderen Versionen verwenden.

<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>
porterhouse91
quelle
1
Ihr Ansatz, da Pascals Problemumgehung Nr. 2 ebenfalls gültig ist, haben Sie auch berücksichtigt, dass die E-Mail-Abhängigkeit als bereitgestellt deklariert werden sollte. Danke dir.
Miguel
Umfang zur Verfügung gestellt hat bei mir nicht funktioniert. Ich habe den Scope-Test verwendet. Bitte überprüfen Sie meine Antwort. stackoverflow.com/a/55970293/4587961
Yan Khonski
3

Am besten machen Sie die Abhängigkeiten, die Sie nicht immer erben möchten, intransitiv.

Sie können dies tun, indem Sie sie im übergeordneten POM mit dem bereitgestellten Bereich markieren.

Wenn das übergeordnete Element weiterhin Versionen dieser Deps verwalten soll, können Sie mit dem <dependencyManagement>Tag die gewünschten Versionen einrichten, ohne sie explizit zu erben oder diese Vererbung an untergeordnete Elemente weiterzugeben .

Ajax
quelle
1

Wenn Sie ein Paket aufrufen, aber einige seiner Abhängigkeiten nicht möchten, können Sie Folgendes tun (in diesem Fall wollte ich nicht, dass das alte log4j hinzugefügt wird, weil ich das neuere verwenden musste):

<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>

Das funktioniert bei mir ... aber ich bin ziemlich neu in Java / Maven, also ist es vielleicht nicht optimal.

bastienb1991
quelle
Willkommen bei Stack Overflow, und lassen Sie sich nicht von den unhöflichen Leuten, die ich ständig meine Fragen entlassen habe, vom Posten abhalten.
Sridhar Sarnobat
1

Ich musste wirklich dieses schmutzige Ding machen ... Hier ist wie

Ich habe diese Abhängigkeiten mit Umfang neu definiert test. Scope providedhat bei mir nicht funktioniert.

Wir verwenden das Spring Boot Plugin, um ein dickes Glas zu bauen. Wir haben ein gemeinsames Modul , das allgemeine Bibliotheken definiert, zum Beispiel Springfox swagger-2. Mein Super-Service muss gemeinsame Eltern haben (das will er nicht, aber die Unternehmensregeln erzwingen!)

Also hat mein Elternteil oder Commons 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>

Und mein Super-Service- Pom.

<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>

Dies ist die Größe des endgültigen Fettartefakts

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

Auch diese Antwort ist erwähnenswert - ich wollte es tun, aber ich bin faul ... https://stackoverflow.com/a/48103554/4587961

Yan Khonski
quelle
0

Wir können das übergeordnete pom als Abhängigkeit vom Typ pom hinzufügen und davon ausschließen. Weil sowieso Eltern-POM heruntergeladen wird. Das hat bei mir funktioniert

<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
quelle