Android X + Truth + Guava test compile issue

23
February 12, 2019, at 04:10 AM

I have an Android library (called api) gradle module as part of a larger project. I just migrated the whole project to AndroidX. I now have this error when running instrumentation test on the 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)

If I check the runtime class path for the debugAndroidTest variant:

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

I get this output. I can see the problem:

------------------------------------------------------------
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 core is depending on the new "ListableFuture-only" build of guava and Truth is depending on the full Guava 25.

I think I understand the underlying problem with ListenableFuture: https://groups.google.com/forum/#!topic/guava-announce/Km82fZG68Sw

What is the right solution here?

I don't want to exclude Guava from Truth entirely (otherwise Truth won't compile)

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

Can I exclude + force update to Guava 27 by making it a first-level dependency:

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'

If I do this, should I be using the android or JRE version of guava?

Side question:

Why don't I see the guava dependency when looking at compile classpath? The error is a compile time error, not a runtime error

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

Resulting 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?
READ ALSO
Remove native base FABs ripple effect on android

Remove native base FABs ripple effect on android

I'm having problem with native base FAB button it shows a square ripple effect when i press it

45
Any idea how to create an elegant ripple effect for audio recording button - as in Google Keep

Any idea how to create an elegant ripple effect for audio recording button - as in Google Keep

Google Keep's audio recording dialog, as a nice ripple effect around the recording button, when you perform voice recording

33
How to run emulator64-arm in a Docker container?

How to run emulator64-arm in a Docker container?

I tried to run emulator64-arm in a Docker container but it reported:

54