Est-il possible d'exclure des artefacts hérités d'un POM parent?

119

Les artefacts des dépendances peuvent être exclus en déclarant un <exclusions>élément à l'intérieur d'un <dependency>Mais dans ce cas, il est nécessaire d'exclure un artefact hérité d'un projet parent. Voici un extrait du POM en discussion:

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

baseartefact, dépend javax.mail:mail-1.4.jaret ALL-DEPSdépend d'une autre version de la même bibliothèque. En raison du fait que mail.jarde ALL-DEPSexist sur l'environnement d'exécution, bien que non exporté, entre en conflit avec le mail.jarqui existe sur le parent, qui est défini comme compile.

Une solution pourrait être de débarrasser mail.jar du POM parent, mais la plupart des projets qui héritent de la base en ont besoin (comme c'est une dépendance transtive pour log4j). Donc, ce que je voudrais faire, c'est simplement exclure la bibliothèque parent du projet enfant , comme cela pourrait être fait s'il bases'agissait d'une dépendance et non du pom parent:

...
    <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
la source

Réponses:

49

Quelques idées:

  1. Peut-être que vous ne pourriez tout simplement pas hériter du parent dans ce cas (et déclarer une dépendance à baseavec l'exclusion). Pas pratique si vous avez beaucoup de choses dans le pom parent.

  2. Une autre chose à tester serait de déclarer l' mailartefact avec la version requise par ALL-DEPSsous le dependencyManagementdans le pom parent pour forcer la convergence (même si je ne suis pas sûr que cela résoudra le problème de portée).

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. Ou vous pouvez exclure la maildépendance de log4j si vous n'utilisez pas les fonctionnalités qui en dépendent (et c'est ce que je ferais):
<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. Ou vous pouvez revenir à la version 1.2.14 de log4j au lieu de la version hérétique 1.2.15 (pourquoi n'ont-ils pas marqué les dépendances ci-dessus comme optionnelles ?!).
Pascal Thivent
la source
Merci pour votre réponse. Il contient de nombreuses informations utiles. Concernant 1) Comme vous l'avez remarqué, ce ne sera pas optimal car le pom parent contient non seulement des dépendances qui seront résolues de manière transitoire si la base a été marquée comme une dépendance, mais aussi des rapports communs, la gestion des sources et d'autres éléments réutilisés dans tous les projets de l'entreprise. En ce qui concerne 2) je l'ai essayé, mais aussi en spécifiant la portée de l'artefact comme prévu, et cela a fonctionné :). Au début, je pensais que la compilation ayant priorité sur fourni, cela ne fonctionnera pas, mais heureusement je me suis trompé (le POM enfant remplace la configuration du parent)
Miguel
29

Vous pouvez regrouper vos dépendances dans un projet différent avec un packaging pomcomme décrit par les bonnes pratiques de 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>

et référencez-les à partir de votre parent-pom (regardez la dépendance <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>

Votre projet enfant hérite de ce parent-pom comme auparavant. Mais maintenant, la dépendance de messagerie peut être exclue dans le projet enfant dans le dependencyManagementbloc:

<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
la source
4
+1 pour cela, bien que l'enfant pom devrait utiliser la section <dependencies> plutôt que <dependencyManagement> puisque ce dernier sert à gérer les versions des dépendances à partir d'un pom parent.
Matthew Wise
1
Ceci est également connu sous le nom de nomenclature, aka nomenclature :-)
Pim Hazebroek
Cela fonctionne-t-il uniquement avec les dépendances transitives? Mon pom parent contient log4j et cela empêche la connexion de mon pom de fonctionner correctement.
Sridhar Sarnobat
10

N'utilisez pas de pom parent

Cela peut sembler extrême, mais de la même manière «l'enfer de l'héritage» est une raison pour laquelle certaines personnes tournent le dos à la programmation orientée objet (ou préfèrent la composition à l'héritage ), supprimez le <parent>bloc problématique et copiez et collez tout <dependencies>ce dont vous avez besoin (si votre équipe vous donne cette liberté).

L'hypothèse selon laquelle le fractionnement des poms en un parent et un enfant pour "réutiliser" et "éviter la redondance" doit être ignorée et vous devez d'abord servir vos besoins immédiats (le remède est pire que la maladie). En outre, la redondance a ses avantages - à savoir l'indépendance des changements externes (c'est-à-dire la stabilité).

C'est plus facile qu'il n'y paraît si vous générez le pom effectif (eclipse le fournit mais vous pouvez le générer à partir de la ligne de commande avec mvn help:effective).

Exemple

Je veux utiliser logbackcomme liaison slf4j, mais mon pom parent inclut la log4jdépendance. Je ne veux pas aller et avoir à pousser la dépendance des autres enfants à log4j dans leurs propres pom.xmlfichiers pour que le mien ne soit pas obstrué.

Sridhar Sarnobat
la source
1
Documentez ceci (et la procédure que vous avez suivie) très attentivement car les futurs responsables doivent le refaire s'ils ont besoin d'utiliser une version mise à jour du pom parent.
Thorbjørn Ravn Andersen
Vous voulez sûrement dire ne pas utiliser les dépendances dans le pom parent? Parent pom est toujours très utile pour gérer les versions de dépendances et les plugins courants. Le simple fait de l'utiliser pour injecter une dépendance peut se retourner contre nous - nous l'utilisons uniquement pour les dépendances indispensables (comme un ensemble de démarreurs de démarrage à ressort essentiels pour un parent pour les microservices)
Amit Goldstein
Non, je ne dis pas d'utiliser un pom parent léger. Les autres membres de votre équipe ne vous permettront pas de couper le pom parent car d'autres applications dépendent des fichiers indésirables du pom parent que vous ne voulez pas.
Sridhar Sarnobat
8

Redéfinissez la dépendance (dans le pom enfant) avec le scopesystème pointant vers un pot vide:

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

Le jar ne peut contenir qu'un seul fichier vide:

touch empty.txt
jar cvf empty.txt
Bax
la source
Merci pour votre réponse, sous Windows 10 j'ai dû courir notepad empty.classensuite jar cvf empty.jar empty.classpour générer un pot vide.
Rov
1
On dirait une mauvaise pratique
Piotr Żak
6

Avez-vous essayé de déclarer explicitement la version de mail.jar souhaitée? La résolution des dépendances de Maven doit l'utiliser pour la résolution des dépendances sur toutes les autres versions.

<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
la source
1
Votre approche, comme la solution de contournement n ° 2 de Pascal est également valable, en fait, vous avez également pris en compte le fait que la dépendance de messagerie doit être déclarée comme fournie. Je vous remercie.
Miguel
La portée fournie n'a pas fonctionné pour moi. J'ai utilisé le test de portée, veuillez vérifier ma réponse. stackoverflow.com/a/55970293/4587961
Yan Khonski
3

Le mieux est de rendre les dépendances dont vous ne voulez pas toujours hériter de manière intransitive.

Vous pouvez le faire en les marquant dans le pom parent avec la portée fournie.

Si vous souhaitez toujours que le parent gère les versions de ces deps, vous pouvez utiliser la <dependencyManagement>balise pour configurer les versions souhaitées sans les hériter explicitement, ni transmettre cet héritage aux enfants.

Ajax
la source
1

Lorsque vous appelez un package mais que vous ne voulez pas certaines de ses dépendances, vous pouvez faire une chose comme celle-ci (dans ce cas, je ne voulais pas que l'ancien log4j soit ajouté car j'avais besoin d'utiliser le plus récent):

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

Cela fonctionne pour moi ... mais je suis assez nouveau sur java / maven donc ce n'est peut-être pas optimal.

bastienb1991
la source
Bienvenue dans Stack Overflow, et ne laissez pas les gens impolis que j'ai constamment rejeter mes questions vous décourager de publier.
Sridhar Sarnobat
1

J'avais vraiment besoin de faire ce sale truc ... Voici comment

J'ai redéfini ces dépendances avec une portée test. La portée providedn'a pas fonctionné pour moi.

Nous utilisons le plugin Spring Boot pour créer un gros pot. Nous avons un module commun qui définit des bibliothèques communes, par exemple Springfox swagger-2. Mon super-service doit avoir des parents communs (il ne veut pas le faire, mais les règles de l'entreprise s'imposent!)

Donc, mes parents ou mes communs ont du 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>

Et mon pom super-service .

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

C'est la taille de l'artefact gras final

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

Cette réponse mérite également d'être mentionnée - je voulais le faire, mais je suis paresseux ... https://stackoverflow.com/a/48103554/4587961

Yan Khonski
la source
0

Nous pouvons ajouter le parent pom en tant que dépendance avec le type pom et faire une exclusion à ce sujet. Parce que de toute façon le pom parent est téléchargé. Cela a fonctionné pour moi

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