気をつけたいGradleの推移的依存関係とその解決

  • 35
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

Gradleはライブラリの依存関係を上手に管理してくれるすぐれものですが、まれに突拍子もない不具合が発生する場合があります。しばらく前にGradleの推移的依存関係でハマったことがあったので、その具体的現象と原因、解決方法についてまとめておきました。

推移的依存関係とは?

Gradleのドキュメント読んでも、ほへー、位の感想なんで、こちらのサイトがわかりやすかったです。端的に言うと、複数のライブラリがあるライブラリ(A)に依存している場合、Aはバージョンが一番最新のものが適用されるということです。

なお推移的(transtive)とは言葉として??って感じでしたが、数学用語なんですね。wikipediaで説明を読むとなるほどなーという感じです。

具体的な事象

ある時、Pureeのバージョンアップ(3.3.0 -> 4.1.0)したところ、releaseのみビルドがfailしました。理由はPuree内で javax.annotation.ParametersAreNonnullByDefault が参照できないからとのこと。

/home/travis/build/project/testProject/app/src/main/java/com/testProject/test/log/OutBufferedLogcat.java:54: error: cannot find symbol @Nonnull
error: cannot access ParametersAreNonnullByDefault
  class file for javax.annotation.ParametersAreNonnullByDefault not found

ParametersAreNonnullByDefault から参照しているライブラリを確認すると、なぜか Crashlytics内のannotationを参照しています。Crashlyticsのannotationには ParametersAreNonnullByDefault がないため、エラーが発生しているというわけです。

Screen Shot 2015-12-11 at 18.36.43.png

なお以下がbuild.gradleの依存関係(抜粋)です。

build.gradle
dependencies {
    compile('com.crashlytics.sdk.android:crashlytics:2.5.0@aar') {
        transitive = true;
    }
    devCompile 'com.facebook.stetho:stetho:1.1.1'
    devCompile 'com.facebook.stetho:stetho-urlconnection:1.1.1'
    compile 'com.cookpad.puree:puree:4.1.1'
    configurations.all {
        resolutionStrategy.force 'com.android.support:support-annotations:23.0.1'
        resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
    }
}

resolutionStrategyで support-annotationsfindbugについては強制的にバージョン適用されているとわかります。

原因

結論から言いますと、ReleaseビルドではGradleが推移的関係にあるライブラリを探した結果、 "該当するものあったけどちょっと違うやつだわー、ゴメン!" というエラーになっているということです。

依存関係は以下のコマンドで調べられます。

./gradlew :app:dependencies

gradleの:app:dependenciesを丹念に調べた結果、以下のことがわかりました。

  • javax.annotation.ParametersAreNonnullByDefaultcom.google.code.findbugs:jsr305:3.0.0 内のannotationが利用されている

  • releaseビルドにはcom.google.code.findbugs:jsr305:3.0.0 が入ってない。理由としては

    • Release以外の場合はStethoを導入している。Stethoは内部的に com.google.code.findbugs:jsr305:3.0.0 に依存しているため、推移的依存が適用されてjavax.annotation.ParametersAreNonnullByDefaultが参照できる。
dependencies
+--- com.facebook.stetho:stetho:1.1.1
|    +--- commons-cli:commons-cli:1.2
|    \--- com.google.code.findbugs:jsr305:2.0.1 -> 3.0.0
+--- com.facebook.stetho:stetho-urlconnection:1.1.1
|    \--- com.google.code.findbugs:jsr305:2.0.1 -> 3.0.0
  • build.gradle内ではconfigurations.allでcom.google.code.findbugsのversionの強制が設定されているものの、compileには入ってないため、Releaseにはjavax.annotationが入っていないです。
build.gradle
configurations.all {
    resolutionStrategy.force 'com.android.support:support-annotations:23.0.1'
    resolutionStrategy.force 'com.google.code.findbugs:jsr305:3.0.0'
}
  • com.google.code.findbugsが入っていないReleaseビルドは推移的依存性によりCrashlyticsにあるannotation配下が参照されます。結果、そこにはjavax.annotation.ParametersAreNonnullByDefaultがないのでエラーになります。

解決策

compile 'com.google.code.findbugs:jsr305:3.0.0' をdependenciesに追加すれば、依存するバージョンが正しくなり、javax.annotation.ParametersAreNonnullByDefaultが参照されるようになりました。

まとめ

わけのわからない依存関係のエラーがでた場合は、

  • なにはともあれdependencies treeで丹念に依存状況とバージョンを確認する
  • 場合によってはライブラリを追加、あるいはライブラリから推移的依存関係となってしまうライブラリをexcludeする

ことをオススメします。