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
がないため、エラーが発生しているというわけです。
なお以下が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-annotations
とfindbug
については強制的にバージョン適用されているとわかります。
#原因
結論から言いますと、ReleaseビルドではGradleが推移的関係にあるライブラリを探した結果、 "該当するものあったけどちょっと違うやつだわー、ゴメン!" というエラーになっているということです。
依存関係は以下のコマンドで調べられます。
./gradlew :app:dependencies
gradleの:app:dependenciesを丹念に調べた結果、以下のことがわかりました。
-
javax.annotation.ParametersAreNonnullByDefault
はcom.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 - Release以外の場合はStethoを導入している。Stethoは内部的に
+--- 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`が入っていないです。
```groovy: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する
ことをオススメします。