Есть ли способ исключить артефакты, унаследованные от родительского POM?

120

Артефакты из зависимостей можно исключить, объявив <exclusions>элемент внутри. <dependency>Но в этом случае необходимо исключить артефакт, унаследованный от родительского проекта. Ниже приводится отрывок из обсуждаемой POM:

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

baseартефакт, зависит javax.mail:mail-1.4.jarи ALL-DEPSзависит от другой версии той же библиотеки. Из-за того, что mail.jarfrom ALL-DEPSсуществует в среде выполнения, хотя и не экспортируется, конфликтует с mail.jarсуществующим в родительской среде , которая имеет область видимости compile.

Решением может быть избавление mail.jar от родительского POM, но большинству проектов, наследующих базу, он нужен (как и переходная зависимость для log4j). Поэтому я хотел бы просто исключить родительскую библиотеку из дочернего проекта , как это можно было бы сделать, если бы baseбыла зависимость, а не родительский pom:

...
    <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
источник

Ответы:

49

Некоторые идеи:

  1. Возможно, в этом случае вы просто не могли бы наследовать от родителя (и объявить зависимость от него baseс исключением). Это не удобно, если в родительском помпе много чего.

  2. Другое дело , чтобы тест был бы объявить mailартефакт с версией , необходимой ALL-DEPSпод dependencyManagementв родительском ПОМ , чтобы заставить конвергенцию (хотя я не уверен , что это позволит решить проблему рамочный).

<dependencyManagement>
  <dependencies>
    <dependency>    
      <groupId>javax.mail</groupId>
      <artifactId>mail</artifactId>
      <version>???</version><!-- put the "right" version here -->
    </dependency>
  </dependencies>
</dependencyManagement>
  1. Или вы можете исключить mailзависимость от log4j, если вы не используете функции, зависящие от него (и это то, что я бы сделал):
<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. Или вы можете вернуться к версии 1.2.14 log4j вместо еретической версии 1.2.15 (почему они не отметили вышеупомянутые зависимости как необязательные ?!).
Паскаль Тивент
источник
Спасибо за ваш ответ. Он содержит много полезной информации. Что касается 1) Как вы заметили, не будет оптимальным, потому что родительский pom не только содержит зависимости, которые транзитивно будут разрешены, если база была помечена как зависимость, но также общие отчеты, управление источниками и другие вещи, повторно используемые в каждом проекте в компании. Что касается 2), я попробовал, но также указал объем артефакта, как указано, и это сработало :). Сначала я подумал, что, поскольку компиляция имеет приоритет над предоставленным, это не сработает, но, к счастью, я ошибся (дочерний POM переопределяет родительскую конфигурацию)
Мигель
29

Вы можете сгруппировать свои зависимости в другом проекте с помощью упаковки, pomкак описано в Sonatypes Best Practices :

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

и ссылайтесь на них из родительского pom (смотрите зависимость <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>

Ваш дочерний проект наследует этот родительский объект, как и раньше. Но теперь почтовую зависимость можно исключить в дочернем проекте внутри dependencyManagementблока:

<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
источник
4
+1 для этого, хотя дочерний pom должен использовать раздел <dependencies>, а не <dependencyManagement>, поскольку последний предназначен для управления версиями зависимостей из родительского pom.
Matthew Wise
1
Это также известно как BOM, или ведомость материалов :-)
Pim Hazebroek
Это работает только с транзитивными зависимостями? Мой родительский pom содержит log4j, и это мешает правильной работе моего pom logback.
Шридхар Сарнобат
10

Не используйте родительский помпон

Это может показаться чрезмерным, но так же, как «ад наследования» - это причина, по которой некоторые люди отворачиваются от объектно-ориентированного программирования (или предпочитают композицию наследованию ), удаляют проблемный <parent>блок и копируют и вставляют все, что <dependencies>вам нужно (если ваша команда дает вам эта свобода).

Предположение, что разделение помпонов на родительский и дочерний для «повторного использования» и «предотвращения повторения» следует игнорировать, и вы должны в первую очередь удовлетворить свои непосредственные потребности (лекарство хуже, чем болезнь). Кроме того, у резервирования есть свои преимущества, а именно независимость от внешних изменений (т.е. стабильность).

Это проще, чем кажется, если вы создаете эффективный pom (eclipse предоставляет его, но вы можете сгенерировать его из командной строки с помощью mvn help:effective).

пример

Я хочу использовать в logbackкачестве привязки slf4j, но мой родительский pom включает log4jзависимость. Я не хочу уходить и вынуждать других детей использовать log4j в их собственных pom.xmlфайлах, чтобы не мешать моим.

Шридхар Сарнобат
источник
1
Очень тщательно задокументируйте это (и процедуру, которой вы следовали), так как будущие сопровождающие должны повторить это, если им потребуется использовать обновленную версию родительского pom.
Thorbjørn Ravn Andersen
Конечно, вы имеете в виду не использовать зависимости в родительском pom? Родительский pom по-прежнему очень полезен для управления версиями зависимостей и общими плагинами. Простое использование его для внедрения зависимостей может иметь неприятные последствия - мы используем его только для обязательных зависимостей (например, набор основных стартеров весенней загрузки для родителя для микросервисов),
Амит Голдштейн
Нет, я не говорю, что используйте легкий родительский помпон. Другие в вашей команде не позволят вам обрезать родительский pom, потому что другие приложения зависят от нежелательного мусора в родительском pom.
Шридхар Сарнобат
8

Переопределите зависимость (в дочернем pom), scopeуказав system на пустую банку:

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

Банка может содержать только один пустой файл:

touch empty.txt
jar cvf empty.txt
Бакс
источник
Спасибо за ваш ответ, на Windows 10 , я должен был бежать notepad empty.classзатем jar cvf empty.jar empty.classгенерировать пустую банку.
Ров
1
Похоже на плохую практику
Петр Чак
6

Вы пытались явно указать версию mail.jar, которую хотите? Разрешение зависимостей Maven должно использовать это для разрешения зависимостей во всех других версиях.

<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
источник
1
Ваш подход, поскольку обходной путь # 2 Паскаля также действителен, на самом деле вы также приняли во внимание, что почтовая зависимость должна быть объявлена ​​как предоставленная. Спасибо.
Мигель
Предоставленный объем не работал у меня. Я использовал тест прицела, проверьте мой ответ. stackoverflow.com/a/55970293/4587961
Ян Хонски
3

Лучше всего сделать зависимости, которые вы не всегда хотите наследовать, непереходными.

Вы можете сделать это, отметив их в родительском pom с предоставленной областью.

Если вы по-прежнему хотите, чтобы родительский элемент управлял версиями этих зависимостей, вы можете использовать <dependencyManagement>тег для настройки версий, которые вам нужны, без их явного наследования или передачи этого наследования дочерним элементам .

Ajax
источник
1

Когда вы вызываете пакет, но не хотите использовать некоторые из его зависимостей, вы можете сделать что-то вроде этого (в этом случае я не хотел добавлять старый log4j, потому что мне нужно было использовать более новый):

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

Это работает для меня ... но я новичок в java / maven, поэтому, возможно, это не оптимально.

bastienb1991
источник
Добро пожаловать в Stack Overflow, и не позволяйте грубым людям, с которыми я постоянно сталкиваюсь, отклонять мои вопросы, отговаривать вас от публикации.
Шридхар Сарнобат
1

Мне действительно нужно было сделать эту грязную вещь ... Вот как

Я переопределил эти зависимости с помощью области видимости test. Сфера providedу меня не сработала.

Мы используем плагин Spring Boot для создания толстой банки. У нас есть модуль common, который определяет общие библиотеки, например Springfox swagger-2. У моего суперсервиса должен быть общий родительский элемент (он не хочет этого делать, но правила компании действуют!)

Итак, у моего родителя или в общем есть пом.

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

И мой суперсервисный пом.

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

Это размер последнего толстого артефакта.

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

Также стоит упомянуть этот ответ - я хотел это сделать, но я ленив ... https://stackoverflow.com/a/48103554/4587961

Ян Хонски
источник
0

Мы можем добавить родительский pom в качестве зависимости от типа pom и исключить его. Потому что в любом случае скачивается родительский пом. Это сработало для меня

<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>
Вики Джайн
источник