web-dev-qa-db-ja.com

Maven依存関係の収束の問題を解決する

Maven-enforcer-pluginを使用して、依存関係の収束の問題を確認します。典型的な出力は次のとおりです。

[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-enforcer-pluginを緩和しています。

私の考えは正しいですか?この問題を処理する別の方法はありますか?一般的なケースに焦点を当てた回答に興味があります-上記のjunitの例は少し奇妙だと思います。

36
Duncan Jones

JUnitをtest以外のスコープに設定しないでください。一般的に言えば、不要な依存関係を排除する以外に別の解決策があるとは考えていません。

簡単なケース:

Andreas Kruegerが言うように、バージョンにはリスクがあるかもしれません(実際に遭遇しました)。プロジェクトの依存関係は次のとおりであるとしましょう:

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

それはあなたのケースの単なる単純化に過ぎないことに注意してください。この依存関係ツリーを見て、projectAで指定された依存関係projectBを除外します。

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

プロジェクトをmavenでパッケージ化すると、残りの依存関係は、3.8.1ではなくgroup2-someProjectB-4.11.jar、バージョン4.11になります。すべてが問題なく、プロジェクトはまったく問題なく実行されます。

それからしばらくして、プロジェクト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、5.0ではなく4.11になります。現時点では、projectAの新しい機能を使用しても、プログラムは正しく実行されません。

ソリューションは何でしたか?

Java-EEプロジェクトでこの問題に遭遇しました。

チームがデータベースサービスを開発しました。彼らはそれをprojectAとしてパッケージ化しました。サービスを更新するたびに、現在のすべての依存関係と現在のバージョンをリストするファイルも更新しました。

ProjectAは、私が取り組んでいたJava-EEプロジェクトの依存関係でした。サービスチームがProjectAを更新するたびに、バージョンの更新も確認しました。

実際、依存関係を除外しても害はありません。ただし、除外が設定されている依存関係を更新するたびに、次のことを確認する必要があります。

  • この除外がまだ理にかなっている場合。
  • 自分のプロジェクトで除外された依存関係のバージョンをアップグレードする必要がある場合。

Mavenの除外は包丁のようなものだと思います。シャープで、野菜を簡単にカットできますが、取り扱いには注意が必要です...

49
user2015707

アーティファクトとしてのJUnitがコンパイルスコープの依存関係として発生している場合は、ライブラリの1つ(ca.juliusdavies)のバグです。

JUnitは常にテスト範囲に含める必要があります。したがって、ビルドが成功すると、生成された.jar、.war、または.earファイルにnotがパックされます。

一般的に、ライブラリ1とライブラリ2が1つの共通の依存関係を共有する場合など、既に含まれている依存関係を除外しても害はありません。

もちろん、発生する可能性がある唯一の問題は、ライブラリ1とライブラリ2に同じ依存アーティファクトの異なるバージョンが含まれている場合です。 これにより、ランタイムエラーが発生する可能性があります、ライブラリの機能が変更された場合。幸いなことに、バージョン番号の違いが大きくない限り、これはよくありません。一般的に、最新の依存バージョンを含め、古いバージョンを除外することをお勧めします。これはほとんどの場合実行可能です。

そうでない場合は、プロジェクトの第1レベルの依存関係に更新があるかどうかを確認します。

3
Andreas Krueger