guava
guava copied to clipboard
update to Guava 32.1.1-android: duplicate classes - not solved by advice in release notes
An Android project would not build correctly but always complain about duplicate classes:
Execution failed for task ':app:checkDebugDuplicateClasses'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
> Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-32.1.1-android (com.google.guava:guava:32.1.1-android) and jetified-listenablefuture-1.0 (com.google.guava:listenablefuture:1.0)
The release notes of 32.1.0 (which are referenced in 32.1.1) said to use
configurations.all {
resolutionStrategy.capabilitiesResolution.withCapability("com.google.collections:google-collections") {
select("com.google.guava:guava:0")
}
// and/or
resolutionStrategy.capabilitiesResolution.withCapability("com.google.guava:listenablefuture") {
select("com.google.guava:guava:0")
}
}
to solve this problem, but it didn't work.
What worked instead was to add:
dependencies {
# dependency definitions here ...
modules {
module("com.google.guava:listenablefuture") {
replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
}
}
}
Thanks. @jjohannes , any advice?
Without more information, I can only guess.
Looks like the conflict is not detected by Gradle's core systems and only checkDebugDuplicateClasses
of the Android plugin is catching this later.
If the conflict is not detected, the capability resolutions strategy from the release notes has no effect.
Question is: why is the conflict not detected?
Could be that this is a bug in Gradle. There have been issues in this area in some versions and there is still one open issue I know of: https://github.com/gradle/gradle/issues/22326 This is not a general problem, but a very specific configuration and combination of dependencies seems to make Gradle miss the conflict.
Would you be able to share some more information about your setup @mathisdt?
- Which Gradle version are you using and, if it is not the latest, could you try updating?
- Can you share a build scan or the output of the
dependencies
task? (if you can't share that in public, you may send me a mail.)
@jjohannes Should be no problem, the app is open source.
I'm using Gradle 8.1.1 at the moment.
When I remove the workaround I mentioned above, the following happens:
# ./gradlew build
> Task :app:processDebugMainManifest
/home/mathis/source-git/trackworktime/app/src/main/AndroidManifest.xml:36:9-42:51 Warning:
provider#org.acra.attachment.AcraContentProvider@android:authorities was tagged at AndroidManifest.xml:36 to replace other declarations but no other declaration present
> Task :app:checkDebugDuplicateClasses FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':app:checkDebugDuplicateClasses'.
> A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable
> Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-32.1.1-android (com.google.guava:guava:32.1.1-android) and jetified-listenablefuture-1.0 (com.google.guava:listenablefuture:1.0)
Go to the documentation to learn how to <a href="d.android.com/r/tools/classpath-sync-errors">Fix dependency resolution errors</a>.
* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.
* Get more help at https://help.gradle.org
BUILD FAILED in 2s
22 actionable tasks: 7 executed, 15 up-to-date
The link of the corresponding build scan is https://scans.gradle.com/s/umgfcfz2bykyy
PS: I just saw that Gradle 8.2 came out two days ago. I updated to 8.2 but the outcome was the same - fine with the workaround, "build failed" without it (also "Duplicate class ..." message).
You can try for yourself, just clone it and remove these lines. That will trigger the error.
Thank you @mathisdt. This is perfect to reproduce the problem. You can see in the build scan, that both guava
(with the new metadata) and listenablefuture:1.0
are on the debugRuntimeClasspath. And both have the com.google.guava:listenablefuture:1.0
capability. So there should be a conflict but Gradle silently accepts it:
For me this look like the issue that I reported – https://github.com/gradle/gradle/issues/22326 – but this is a better reproducer.
Is there anything to do here from the Guava side? Maybe we should mention the workaround in https://github.com/google/guava/issues/6618#issue-1784008950 somewhere. Or just leave this issue open until the Gradle issue is resolved I guess.
I am attempting to update my Android app's guava dependency from 31.1-jre
to 32.1.1-jre
. Updating only that leads to the gradle listenablefuture
conflict mentioned above. So I attempted to apply the "this worked" portion of this comment, like this:
dependencies {
...
implementation 'com.google.guava:guava:32.1.1-jre'
modules {
module("com.google.guava:listenablefuture") {
replacedBy("com.google.guava:guava", "listenablefuture is part of guava")
}
}
...
}
Gradle update now completes successfully, but building fails. Specifically, it seems that a specific subset of guava is missing, consisting of Java 8 methods and AutoValue
processing.
Does anyone have any idea how to make this work? I have no urgent need to upgrade guava in my project, but I do like to stay up to date whenever possible, and I'm also now curious about how to resolve this issue.
Hello, stranger :)
It sounds like the problem may be that our new Gradle metadata is overriding your choice to use the -jre flavor of Guava because you're building an Android app. That means that you get a version that doesn't contain the Streams
class or any Collector
APIs (which also leads to errors that prevent AutoValue from running).
I guess I'm not too surprised that the -jre flavor can work on Android (for people targeting a new enough version or using desugaring), but I wouldn't necessarily have recommended it :) [edit: Update: I thought about it some more in response to another question, and I would recommend against it.]
You might be able to force the JRE flavor by following a tweaked version of the instructions under "Selecting the appropriate flavor," also in the release notes. You'd be tweaking them to replace "ANDROID" with "STANDARD_JVM" (and, if you need the second section, replacing "android" with "jre").
What would be nicer for you is if we implemented https://github.com/google/guava/issues/6567 so that the APIs you need were available on the Android flavor, at which point you could presumably use that.
Hi, I'm a university student at Australian National University. One of my current assignments requires us to finish some issues on OSS. One of the repositories is your project. May I try to take this issue? Just have a ask to make sure whether the issue is solved or not because it is still open and no assignee.
When both guava and listenablefuture are in your dependency tree remember to choose the empty listenablefuture dependency, as the classes are already existing in guava.
implementation 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava'
It has been that way for the last five years:
https://github.com/google/guava/blob/b49353abca20517e449b0a00f66bb5455608290a/futures/listenablefuture9999/pom.xml
@joe61fa6f1awe I don't know if this is really a Guava issue, maybe it is a Gradle problem which has only been triggered by Guava - please see above.
Maybe @cpovirk or @jjohannes can shed some light as to whether this is a good starting point for you?