Gradleプロジェクトで依存関係の競合を解決する

河上です。

前回記事に載せられていなかったので改めて自己紹介を。
関西に住んでフリーエンジニアをやっております。河上です。
よろしくお願いします。

GradleやMavenなどでJavaのプロジェクト構成を管理していて間接的に依存しているライブラリ同士のバージョン競合が起こることってありますよね?

これを「推移的な依存の競合」と呼ぶのですが、今回は単純な例で競合はどのようにして起こり、どう解決するのかを単純な例で示してみたいと思います。

想定するGradleのバージョンは2.1とします。

推移的な依存の競合状態の単純な例

      foo:example:lib-a-1.0.0-RELEASE
         └bar:example:lib-x-2.0.0-REALEASE
      foo:example:lib-b-1.0.0-RELEASE
         └bar:example:lib-x-1.9.0-RELEASE

上記ではlib-xの2.0.0と1.9.0が競合状態にありますがGradleでの推移的依存の解決方法はデフォルトで[Newest:最も新しいバージョンの依存関係を使用する]となっており、このままではlib-x-2.0.0-RELEASEが使用される状態です。

問題はlib-xの2.0.0には下位互換性が無く1.9.0の方を使いたいといった時に、Gradleではどのようにするのか?
ということですが、とりあえず以下の2つの方法を覚えておけば大体のケースに対応できると思います。

 

  • DependencyHandlerでどちらかの推移依存を除外

 

  • ResolutionStrategyで推移依存をどちらかに固定

 

実際に例にある推移的依存のうち古い方のバージョンを採用する形で競合を解決してみると以下のようになります。

1. DependencyHandlerでどちらかの推移依存を除外

      dependency {
         compile('foo:example:lib-a-1.0.0-RELEASE') {
            exclude 'bar:example:lib-x-2.0.0-RELEASE'      
         }
         compile('foo:example:lib-b-1.0.0-RELEASE')
      }

2. ResolutionStrategyで推移依存をどちらかに固定

      dependency {
         compile('foo:example:lib-a-1.0.0-RELEASE')
         compile('foo:example:lib-b-1.0.0-RELEASE')
      }

      configurations.all {
         resolutionStrategy {
            force 'foo:example:lib-x-1.9.0-RELEASE'
         }
      }

まとめ

この他にもResolutionStrategyでは競合が起こった場合はエラーにするような設定ができたりと、競合解決に関する設定がいろいろとあるので是非試してみて下さい。

参考資料:依存関係の管理

補足:なぜこんなに複雑な管理をしなければならないのか?

これはJavaにモジュールシステムと言えるものが無い事が原因だと考えられます。
Javaの実行時の依存ライブラリの関係はすべてフラットで、直接依存しているJarファイルから推移的に依存しているJarファイルまですべてをフラットに含めなければなりません。
もしこれが、直接依存しているJarファイルを指定しておくだけで、そこから推移する依存関係は直接依存しているJarファイルの
名前空間からしかアクセスしないというようなクラスローディングの仕組みがあれば、このような複雑な管理はなくなります。
しかしこれには、重複するJarファイルもすべて直接依存するJarファイルごとに保持しなければならず、アプリケーションのサイズ(warファイルなど)が肥大化してまうというデメリットもあり悩ましいところです。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中