web-dev-qa-db-ja.com

Android X + Truth + Guavaテストコンパイルの問題

大規模なプロジェクトの一部としてAndroidライブラリ(apiと呼ばれる)gradleモジュールを持っています。プロジェクト全体をAndroidXに移行したところです。計測テストを実行すると、このエラーが発生しますapi lib:

 Task :api:checkDebugAndroidTestDuplicateClasses FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':api:checkDebugAndroidTestDuplicateClasses'.
> 1 exception was raised by workers:
  Java.lang.RuntimeException: Java.lang.RuntimeException: Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-25.1-Android.jar (com.google.guava:guava:25.1-Android) and listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)

ランタイムクラスパスでdebugAndroidTestバリアントを確認すると、次のようになります。

./gradlew api:dependencies --configuration debugAndroidTestRuntimeClasspath | grep --color -E "guava|$"

この出力が表示されます。私は問題を見ることができます:

------------------------------------------------------------
Project :api
------------------------------------------------------------
debugAndroidTestRuntimeClasspath - Resolved configuration for runtime for variant: debugAndroidTest
+--- project :test_utils
|    +--- project :core
...
|    +--- project :api (*)
|    +--- com.google.Android.material:material:1.1.0-alpha03
|    |    +--- androidx.annotation:annotation:1.0.1 -> 1.1.0-alpha01
|    |    +--- androidx.appcompat:appcompat:1.1.0-alpha01
|    |    |    +--- androidx.annotation:annotation:1.0.0 -> 1.1.0-alpha01
|    |    |    +--- androidx.core:core:1.1.0-alpha01 -> 1.1.0-alpha03
|    |    |    |    +--- com.google.guava:listenablefuture:1.0 // <------ GUAVA
|    |    |    |    +--- androidx.annotation:annotation:1.0.1 -> 1.1.0-alpha01
...
+--- com.google.truth:truth:0.42
|    +--- com.google.guava:guava:25.1-Android / <------ MORE GUAVA
|    |    +--- com.google.code.findbugs:jsr305:3.0.2
|    |    +--- com.google.errorprone:error_prone_annotations:2.1.3 -> 2.3.1
|    |    +--- com.google.j2objc:j2objc-annotations:1.1
|    |    \--- org.codehaus.mojo:animal-sniffer-annotations:1.14
|    +--- org.checkerframework:checker-compat-qual:2.5.3
|    +--- org.checkerframework:checker-qual:2.5.3
|    +--- junit:junit:4.12 (*)
|    +--- com.googlecode.Java-diff-utils:diffutils:1.3.0
|    +--- com.google.auto.value:auto-value-annotations:1.6.2
|    \--- com.google.errorprone:error_prone_annotations:2.3.1
...

AndroidXコアは新しい「ListableFuture-only」ビルドのguavaに依存しており、Truthは完全なGuava 25に依存しています。

ListenableFutureの根本的な問題を理解していると思います: https://groups.google.com/forum/#!topic/guava-announce/Km82fZG68Sw

ここで正しい解決策は何ですか?

GuavaをTruthから完全に除外したくない(そうしないと、Truthはコンパイルされません)

androidTestImplementation("com.google.truth:truth:0.42") {
    exclude group: 'com.google.guava', module: 'guava'
}

+第一レベルの依存関係にすることで、Guava 27を強制的に除外できますか?

androidTestImplementation("com.google.truth:truth:$rootProject.ext.truthVersion") {
    exclude group: 'com.google.guava', module: 'guava'
}
// must add guava as top level dependency to force Truth to use latest version
androidTestImplementation 'com.google.guava:guava:27.0.1-Android'

これを行う場合、AndroidまたはJREバージョンのguavaを使用する必要がありますか?

副質問:

compileクラスパスを確認すると、グアバ依存関係が表示されないのはなぜですか?エラーは、ランタイムエラーではなく、コンパイル時エラーです。

./gradlew api:dependencies --configuration debugAndroidTestCompileClasspath | grep --color -E "guava|$"

結果のdeps:

debugAndroidTestCompileClasspath - Resolved configuration for compilation for variant: debugAndroidTest
+--- project :test_utils // <----------- why are test_utils deps not listed here???
...
+--- com.google.truth:truth:0.42
|    +--- com.google.guava:guava:25.1-Android <------ GUAVA
|    |    +--- com.google.code.findbugs:jsr305:3.0.2
|    |    +--- org.checkerframework:checker-compat-qual:2.0.0 -> 2.5.3
|    |    +--- com.google.errorprone:error_prone_annotations:2.1.3 -> 2.3.1
|    |    +--- com.google.j2objc:j2objc-annotations:1.1
|    |    \--- org.codehaus.mojo:animal-sniffer-annotations:1.14
|    +--- org.checkerframework:checker-compat-qual:2.5.3
|    +--- org.checkerframework:checker-qual:2.5.3
|    +--- junit:junit:4.12 (*)
|    +--- com.googlecode.Java-diff-utils:diffutils:1.3.0
|    +--- com.google.auto.value:auto-value-annotations:1.6.2
|    \--- com.google.errorprone:error_prone_annotations:2.3.1
...
+--- com.google.truth:truth:{strictly 0.42} -> 0.42 (c)
+--- com.google.guava:guava:{strictly 25.1-Android} -> 25.1-Android (c) // <--------- why is this listed again here at top level?

更新:

Truth 0.43に更新した後、次のエラーが表示されます。

> Could not resolve all artifacts for configuration ':mymodule:debugAndroidTestRuntimeClasspath'.
   > Could not resolve com.google.guava:listenablefuture:{strictly 1.0}.
     Required by:
         project :mymodule
      > Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
           Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-Android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
           Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'andrexampleoidx.core:core:1.1.0-alpha04' --> 'com.google.guava:listenablefuture:1.0'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
            ...
           Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
           ...

   > Could not resolve com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava.
     Required by:
         project :mymodule > com.google.truth:truth:0.43 > com.google.guava:guava:27.0.1-Android
      > Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
           Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-Android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
           Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'com.google.guava:listenablefuture:1.0'
           ...
           Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
           ...

   > Could not resolve com.google.guava:listenablefuture:1.0.
     Required by:
         project :mymodule > androidx.core:core:1.1.0-alpha04
         project :mymodule > androidx.concurrent:concurrent-futures:1.0.0-alpha02
      > Cannot find a version of 'com.google.guava:listenablefuture' that satisfies the version constraints:
           Dependency path 'example:mymodule:unspecified' --> 'com.google.truth:truth:0.43' --> 'com.google.guava:guava:27.0.1-Android' --> 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
           ...
           Dependency path 'example:mymodule:unspecified' --> 'example:myothermodule:unspecified' --> 'androidx.core:core:1.1.0-alpha04' --> 'androidx.concurrent:concurrent-futures:1.0.0-alpha02' --> 'com.google.guava:listenablefuture:1.0'
           Constraint path 'example:mymodule:unspecified' --> 'com.google.guava:listenablefuture:{strictly 1.0}' because of the following reason: debugRuntimeClasspath uses version 1.0
           ...

私が正しく理解している場合:

  • 真実0.43はGuava 27に依存
  • Guava 27は9999.0-emptyに依存しています。これは、内部的にListenableFutureのコピーを含み、バージョン9999.0-emptyが「空」であるためです。
  • androidXコアなどの他のライブラリはlistenablefuture:1.0に依存しています
  • 競合を解決するとき(バージョン1.0または9999.0を使用する必要がありますか?)Gradleは最新バージョン(この場合は9999.0)を選択します。
  • したがって、AndroidXコアは実際に実際にListenableFutureをクラスパスからGuava経由で取得していますが、それだけではありません。
  • ただし、strictlyキーワードは1.0の使用を強制しています
  • Android Gradle Pluginがランタイムとコンパイル時のクラスパスを同じバージョンに依存することを強制するため、これが発生します=( 続きを読む

だから今はどうしたらいいのか悩んでいます。

12
tir38

おそらく「機能する」べきもう1つのことは、アプリ自体(テストだけでなくアプリ全体)をguava:27.0.1-Androidに依存させることです。ビルドでProguardを使用している場合は、ビルド中に(ListenableFutureを除いて)すべて削除されます。そうでない場合でも、特にlistenablefutureトリックとその後のAndroid Gradleの間の悪い相互作用を回避するためだけに、Guavaは大きな依存関係になります。プラグイン:(

0
Chris Povirk