Решение проблем конвергенции зависимостей Maven

Я использую плагин maven-forcer для проверки проблем сходимости зависимостей. Типичный результат будет:

[WARNING] Rule 1: org.apache.maven.plugins.enforcer.DependencyConvergence failed 
  with message:
Failed while enforcing releasability the error(s) are [
Dependency convergence error for junit:junit:3.8.1 paths to dependency are:
+-foo:bar:1.0-SNAPSHOT
  +-ca.juliusdavies:not-yet-commons-ssl:0.3.9
    +-commons-httpclient:commons-httpclient:3.0
      +-junit:junit:3.8.1
and
+-foo:bar:1.0-SNAPSHOT
  +-junit:junit:4.11
]

Видя это сообщение, я обычно "решаю" его, исключая транзитивную зависимость, например

<dependency>
  <groupId>ca.juliusdavies</groupId>
  <artifactId>not-yet-commons-ssl</artifactId>
  <version>0.3.9</version>
  <exclusions>
    <!-- This artifact links to another artifact which stupidly includes 
      junit in compile scope -->
    <exclusion>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Я хотел бы понять, действительно ли это исправление и риски, связанные с исключением библиотек таким образом. Как я вижу это:

  • Исправление обычно безопасно при условии, что я выбрал более новую версию. Это зависит от авторов библиотеки, поддерживающих обратную совместимость.

  • Как правило, это не влияет на сборку Maven (поскольку побеждает более близкое определение), однако, исключая зависимость, я говорю Maven, что знаю об этой проблеме, и, таким образом, успокаиваю плагин maven-inspecer-plugin.

Правильны ли мои мысли и есть ли альтернативный способ решения этой проблемы? Я заинтересован в ответах, которые сосредоточены на общем случае - я понимаю, junit Пример выше немного странный.

3 ответа

Решение

Мы все согласны с тем, что JUnit никогда не следует устанавливать в другую область, чем test, Вообще говоря, я тоже не думаю, что есть иное решение, кроме исключения нежелательной зависимости, поэтому мы все согласны с тем, что вы правы в этом.

ПРОСТОЙ СЛУЧАЙ:

Как говорит Андреас Крюгер, с версиями может быть риск (я действительно сталкивался с ним). Допустим, что зависимости проекта следующие:

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:2.0
     +-group2:projectB:3.8.1
  +-group2:projectB:4.11

Обратите внимание, что это всего лишь упрощение вашего случая. Видя это дерево зависимостей, вы бы исключили зависимость projectB, заданную projectA:

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>2.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>

После упаковки проекта с помощью maven оставшейся зависимостью будет group2-someProjectB-4.11.jar, версия 4.11, а не 3.8.1. Все будет хорошо, и проект будет работать без каких-либо проблем.

Затем, через некоторое время, допустим, вы решили перейти на следующую версию проекта A, версию 3.0, которая добавляет новые замечательные функции:

<dependency>
  <groupId>group1</groupId>
  <artifactId>projectA</artifactId>
  <version>3.0</version>
  <exclusions>
    <exclusion>
      <groupId>group2</groupId>
      <artifactId>projectB</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Проблема в том, что вы еще не знаете, что projectA версии 3.0 также обновило свою зависимость projectB до версии 5.0:

+-foo:bar:1.0-SNAPSHOT
  +-group1:projectA:3.0
     +-group2:projectB:5.0
  +-group2:projectB:4.11

В этом случае исключение, которое вы сделали бы некоторое время назад, исключает ProjectB версии 5.0.

Однако ProjectA версии 3.0 требует улучшений по сравнению с проектом B версии 5.0. Из-за исключения после упаковки проекта с помощью maven оставшейся зависимостью будет group2-someProjectB-4.11.jar, версия 4.11, а не 5.0. В настоящее время вы используете любую из новых функций ProjectA, программа не будет работать правильно.

ЧТО ТАКОЕ РЕШЕНИЕ?

Я столкнулся с этой проблемой в проекте Java-EE.

Команда разработала базу данных сервисов. Они упаковали это как projectA. Каждый раз, когда они обновляли службы, они также обновляли файл, в котором перечислены все их текущие зависимости и текущие версии.

ProjectA был зависимостью для проекта Java-EE, над которым я работал. Каждый раз, когда сервисная команда обновляла ProjectA, я также проверял обновления версий.

На самом деле, нет никакого вреда в исключении зависимости. Но каждый раз, когда вы обновляете зависимость, где было установлено исключение, вы должны проверять:

  • если это исключение все еще имеет смысл.
  • если вам нужно обновить версию исключенной зависимости в вашем собственном проекте.

Я предполагаю, что исключения из мавена похожи на кухонные ножи. Он острый, нарезает овощи без усилий, но требует осторожности при обращении с ним...

Если JUnit как артефакт становится зависимостью в области компиляции, это ошибка одной из ваших библиотек, здесь: ca.juliusdavies.

JUnit всегда должен быть включен в область тестирования. Таким образом, при успешной сборке он не упаковывается в полученный файл.jar, .war или.ear.

Вообще говоря, нет никакого вреда в исключении уже включенных зависимостей, как, например, когда библиотека 1 и библиотека 2 имеют одну общую зависимость.

Конечно, единственная проблема, которая может возникнуть, заключается в том, что библиотека 1 и библиотека 2 содержат разные версии одного и того же зависимого артефакта. Это может привести к ошибкам во время выполнения, когда функции библиотеки изменились. К счастью, это не всегда так, если только разница в номерах версий не велика. Как правило, рекомендуется включать последнюю версию зависимости и исключать более старую. Это в большинстве случаев жизнеспособно.

Если нет, проверьте, есть ли обновления для зависимостей первого уровня вашего проекта.

Лучший способ решить эту проблему с зависимостями при использовании Enforcer в проекте. Следует добавить ошибку, вызывающую зависимость в управлении зависимостями, т.е. pom.xml, как в этом junit, вызывает проблему, поэтому выберите более высокую версию и добавьте как зависимость в pom.xml

                  <dependency><groupId>junit_or_group_id_error_causing_dependency</groupId><artifactId>Junit_or_artifact_id_group_id_error_causing_dependency</artifactId><version>4.11_or_higher_version_of_error_causing_dependency</version></dependency>

Исключение может быть другим решением, но я нашел более чистый способ сделать то же самое.

Другие вопросы по тегам