めちゃくちゃ嵌ったので記録しておきます。まとまらないけど。
あと、Kotlinはあまり関係ないかも。
TL;DR
- dependenciesに書く順番が大事
- Dagger 2.2以降とOrmaを使う場合は
com.google.dagger:dagger-compiler:2.x
より前に'com.squareup:javapoet:1.6.1'
をapt/kaptに指定する - Kotlin + databinding + Dagger2 + Android Studio 2.1 Preview 5 以降の組み合わせのとき、
com.google.dagger:dagger-compiler:2.x
や'com.android.databinding:compiler:2.1.0-[preview|beta]x'
より前に'com.google.guava:guava:[18.0|19.0]'
をapt/kaptに指定する
事の始まり
以下の構成となっているプロジェクトで作業していました。
- Android Studio 2.1 Preview 4 (
com.android.tools.build:gradle:2.1.0-alpha4
) - Kotlin 1.0.1-2
- Databinding
- Dagger 2.0.2
- Orma 2.4.0
Android Studio 2.1 Preview 5 がリリースされたタイミングで作業環境もアップデート。
すると、エラーが出てコンパイルできなくなりました。
java.lang.NoSuchMethodError:com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable;
Android Studio 2.1 Beta 3がリリースされるまで修正を期待して待ったのですが解決される気配がないので調べました。
Dagger 2.0.2 + Android Studio 2.1 Preview 5 or after
java.lang.NoSuchMethodError:com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable;
見つからないメソッドはGuava 18.0から
/**
* Returns a fluent iterable whose iterators traverse first the elements of this fluent iterable,
* followed by those of {@code other}. The iterators are not polled until necessary.
*
* <p>The returned iterable's {@code Iterator} supports {@code remove()} when the corresponding
* {@code Iterator} supports it.
*
* @since 18.0
*/
@Beta
@CheckReturnValue
public final FluentIterable<E> append(Iterable<? extends E> other) {
return from(Iterables.concat(iterable, other));
}
このissueによるとDaggerで使われているGuavaは18.0だが、それより下のバージョンが使われているらしい。
なるほど?
$ ./gradlew app:dependencies --configuration=kapt
kapt
+--- org.jetbrains.kotlin:kotlin-annotation-processing:1.0.1-2
| \--- org.jetbrains.kotlin:kotlin-stdlib:1.0.1-2
| \--- org.jetbrains.kotlin:kotlin-runtime:1.0.1-2
+--- com.android.databinding:compiler:2.1.0-beta3
| +--- com.android.databinding:baseLibrary:2.1.0-beta3
| \--- com.googlecode.juniversalchardet:juniversalchardet:1.0.3
+--- com.github.gfx.android.orma:orma-processor:2.4.0
| +--- com.github.gfx.android.orma:orma-annotations:2.4.0
| \--- com.squareup:javapoet:1.6.1
+--- com.google.dagger:dagger-compiler:2.0.2
| +--- com.google.dagger:dagger:2.0.2
| | \--- javax.inject:javax.inject:1
| +--- com.google.dagger:dagger-producers:2.0-beta
| | +--- com.google.dagger:dagger:2.0 -> 2.0.2 (*)
| | \--- com.google.guava:guava:18.0
| \--- com.google.guava:guava:18.0
(以下省略)
(*) - dependencies omitted (listed previously)
確かにDaggerが依存しているGuavaは18.0だ。
$ ./gradlew app:assembleDebug --debug | grep guava > temp.txt
01:24:12.662 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder] Visiting dependency com.android.tools.build:gradle-api:2.1.0-beta3(runtime) -> com.google.guava:guava:17.0(runtime)
01:24:12.662 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.resolveengine.graph.DependencyGraphBuilder] Selecting new module version com.google.guava:guava:17.0
01:24:12.662 [DEBUG] [org.gradle.api.internal.artifacts.ivyservice.ivyresolve.RepositoryChainComponentMetaDataResolver] Attempting to resolve component for com.google.guava:guava:17.0 using repositories [BintrayJCenter, maven, maven2]
...
どうやら、build tools の gradle plugin が Guava 17.0に依存していて、どういうわけかビルド時にもそちらが使われてしまうらしい。
issueにはDaggerを2.1以上にすれば解決すると書かれているので最新の2.3で試してみることにする。
Dagger 2.3 + Orma 2.4.0
しかし、ビルドエラーになる。
java.lang.NoSuchMethodError: com.squareup.javapoet.TypeSpec.classBuilder(Lcom/squareup/javapoet/ClassName;)Lcom/squareup/javapoet/TypeSpec$Builder;
今度はJavaPoetのメソッドが見つからないらしい...
これについてもissueが上がっていた。
DaggerがJavaPoetを内蔵しているせいで古いJavaPoetが使われてしまうらしい。
Orma作者の__gfx__さんもこう言ってた。
OrmaとDagger 2.2を一緒に使うとJavaPoetでNoMethodErrorがでるの、dagger-compiler.jar にある古いJavaPoetが参照されるせいです。Daggerをダウングレードすると動くはず。 https://t.co/laMQuq98O8
— FUJI Goro (@__gfx__) April 4, 2016
ただ、こんなTweetも見つけたので
お、kaptにjavapoet直接指定したら最新のdaggerでormaビルドできるっぽいぞ
— せーい(yshrsmz) (@_yshrsmz) April 11, 2016
試しに以下のようにkaptでjavapoetを明示してみた。
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
kapt "com.android.databinding:compiler:2.1.0-beta3"
compile("com.github.gfx.android.orma:orma:2.4.0") {
exclude group: 'com.tunnelvisionlabs', module: 'antlr4-runtime'
exclude group: 'com.tunnelvisionlabs', module: 'antlr4-annotations'
}
kapt "com.github.gfx.android.orma:orma-processor:2.4.0"
kapt 'com.squareup:javapoet:1.6.1'
compile 'com.google.dagger:dagger:2.3'
kapt 'com.google.dagger:dagger-compiler:2.3'
...
すると…
java.lang.NoSuchMethodError: com.google.common.collect.ImmutableSetMultimap$Builder.putAll(Ljava/lang/Iterable;)Lcom/google/common/collect/ImmutableSetMultimap$Builder;
さっきまでとは違うエラーだ...
ちなみに、Dagger 2.2に下げると
java.lang.NoSuchMethodError:com.google.common.collect.FluentIterable.append(Ljava/lang/Iterable;)Lcom/google/common/collect/FluentIterable;
最初の問題、解決してなかったじゃんか...
Dagger 2.3 + Databinding
(2016/04/21追記)
このエラーが出る原因についてはこちらのコメント参照
(追記ここまで)
こちらの記事(AndroidでKotlinを使ったDagger2)にもあるように、ImmutableSetMultimap$Builder.putAll
が見つからないのはDagger 2.3からのようです。
issueのコメントによると、dagger-compiler
より先にguava
を明示するとよいとのこと。
ただ、自分の構成ではkaptのdatabindingより先に明示しないと動きませんでした。
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
kapt 'com.google.guava:guava:19.0'
kapt "com.android.databinding:compiler:2.1.0-beta3"
compile("com.github.gfx.android.orma:orma:2.4.0") {
exclude group: 'com.tunnelvisionlabs', module: 'antlr4-runtime'
exclude group: 'com.tunnelvisionlabs', module: 'antlr4-annotations'
}
kapt "com.github.gfx.android.orma:orma-processor:2.4.0"
kapt 'com.squareup:javapoet:1.6.1'
compile 'com.google.dagger:dagger:2.3'
kapt 'com.google.dagger:dagger-compiler:2.3'
...
}
ここまでやってついにビルドが成功しました...
この状態からDaggerを2.2や2.0.2にダウングレードしても問題なくビルドできます。今までの苦労はいったい...
JavaPoetの指定場所
ビルドには成功したのですが、dependenciesに書く順番によって有効になったりならなかったりするのが割と衝撃でした。
そして、気になってDaggerとOrmaの問題で追加したJavaPoet
の指定をdagger-compiler
より後ろにしたらどうなるのか試してみると...
java.lang.NoSuchMethodError: com.squareup.javapoet.TypeSpec.classBuilder(Lcom/squareup/javapoet/ClassName;)Lcom/squareup/javapoet/TypeSpec$Builder;
やはりこちらも指定の順番が重要なようです。
消耗した...
おわりに
dependenciesに書く順番が結果に影響するのが意外すぎました。aptこわい。