guava: guava:32.1.1-jre conflicts with google-cloud-datastore:2.16.0
Using gradlew 7.4, this build.gradle
file:
apply plugin: 'java'
repositories {
mavenCentral()
}
dependencies {
implementation 'com.google.cloud:google-cloud-datastore:2.16.0'
implementation 'com.google.guava:guava:32.1.1-jre'
}
print configurations.runtimeClasspath.files
…fails like this:
$ gradlew dependencies
FAILURE: Build failed with an exception.
* Where:
Build file '/tmp/gradle-guava-error/build.gradle' line: 13
* What went wrong:
A problem occurred evaluating root project 'test'.
> Could not resolve all files for configuration ':runtimeClasspath'.
> Could not resolve com.google.guava:guava:32.1.1-jre.
Required by:
project :
> Module 'com.google.guava:guava' has been rejected:
Cannot select module with conflict on capability 'com.google.guava:listenablefuture:1.0' also provided by [com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava(runtime)]
> Could not resolve com.google.guava:guava:31.0.0-jre.
Required by:
project :
> Module 'com.google.guava:guava' has been rejected:
Cannot select module with conflict on capability 'com.google.guava:listenablefuture:1.0' also provided by [com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava(runtime)]
> Could not resolve com.google.guava:guava:32.0.1-jre.
Required by:
project : > com.google.cloud:google-cloud-datastore:2.16.0
> Module 'com.google.guava:guava' has been rejected:
Cannot select module with conflict on capability 'com.google.guava:listenablefuture:1.0' also provided by [com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava(runtime)]
> Could not resolve com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava.
Required by:
project : > com.google.cloud:google-cloud-datastore:2.16.0
project : > com.google.cloud:google-cloud-datastore:2.16.0 > com.google.api.grpc:grpc-google-cloud-datastore-admin-v1:2.16.0
> Module 'com.google.guava:listenablefuture' has been rejected:
Cannot select module with conflict on capability 'com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava' also provided by [com.google.guava:guava:32.1.1-jre(jreRuntimeElements)]
* 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 314ms
It succeeds with 32.0.1-jre or if excluding the transitive listenablefuture dependency from datastore:
implementation dependencies.create('com.google.cloud:google-cloud-datastore:2.16.0') {
exclude group: 'com.google.guava', module: 'listenablefuture'
}
About this issue
- Original URL
- State: closed
- Created a year ago
- Reactions: 2
- Comments: 16 (14 by maintainers)
Commits related to this issue
- Under Gradle, return to having `guava` automatically pull in the empty `listenablefuture-9999....jar` instead of making Gradle report a conflict that users need to [resolve](https://github.com/google/... — committed to google/guava by cpovirk a year ago
- Under Gradle, return to having `guava` automatically pull in the empty `listenablefuture-9999....jar` instead of making Gradle report a conflict that users need to [resolve](https://github.com/google/... — committed to google/guava by cpovirk a year ago
Thank you for the explanations.
I don’t understand though why
<flattenDependencyMode>all</flattenDependencyMode>
is used in the first place. It causes libraries to declare dependencies they don’t have. Which can cause all kind of unexpected behaviour. Especially if you expect folks to update some of the used libraries to a different version. Like you expect things to keep working with a newer Guava version which this issue is about.You can’t expect a tool like Gradle or Maven to keep doing good automatic conflict resolution if you feed it wrong metadata. This is a general problem with the flattenDependencyMode setup in google-cloud-shared-config. This issue is just one of the things that can happen (and now happened). If Guava would make other changes to its dependencies, you can run into different trouble - with Gradle or Maven alike.
The fix for me is clearly to not do
<flattenDependencyMode>all</flattenDependencyMode>
. You can also use the omitExclusions as @cpovirk suggested. But then you should also exclude the other dependencies you don’t have (probably the annotation libraries Guava brings in). It would be much clearer if you only declare the dependencies you need.As for the current situation: There is nothing broken from my perspective. Users can address the capability conflicts as described further up. I think changing something in the Guava metadata in the next release would be the wrong thing to do. If you do that as a reaction to the discussion here, you admit that you cannot change anything in the dependencies ever, because upstream consumers decided to blindly copy your dependencies at a point in the past and now you are “locked in” because of them.
This should be fixed in
google-cloud-shared-config
.One other thing I might try to look into: Would it be better if Guava claimed to serve as an implementation of version 9999… of listenablefuture instead of version 1?
The source of grpc-google-cloud-datastore-admin-v1 is https://github.com/googleapis/java-datastore/blob/main/grpc-google-cloud-datastore-admin-v1/pom.xml. Its parent is google-cloud-shared-config https://github.com/googleapis/java-shared-config/blob/main/pom.xml#L238, which uses flatten-maven-plugin with
<flattenDependencyMode>all</flattenDependencyMode>
:That’s new information to me. Thank you. I was only looking at its pom.xml where it shows:
cpovirk has shared https://github.com/google/guava/blob/347ef4ec219fed3b2801c094d800af1dd5be1a76/guava/module.json to me. (A
module.json
file is new to me.) I guess it’sdependencies
section, which does not have thelistenablefuture
is the part you’re referencing:For future releases, it might work. But I have concern about the restriction that Gradle users cannot use the latest Guava and Google Cloud libraries prior to August 2023 together.
The “right” way to solve the conflict would be to add this resolution strategy as suggested in the release notes:
What I am surprised about is that you get a
9999.0-empty-to-avoid-conflict-with-guava
version from another place than Guava. Why would any other library have a dependency to that? For me it looks like the metadata of that library – in this casecom.google.api.grpc:grpc-google-cloud-datastore-admin-v1
– is wrong and something should be fixed there. Looking at that particular metadata. It seems to be – excuse my wording – bogus. It re-lists all transitive dependencies of Guava. The problem for me is clearly there and not in Guava.It would be very sad to add the dependency to an empty Jar back to Guava. From my perspective, this is bad practice as everyone using Guava ends up with an empty Jar polluting there runtime classpath – shipping as part of their application in many cases - until they explicitly remove it. I consider removing these unneeded runtime dependencies one of the main advantages with the Gradle metadata. If we make these compromises, we could IMO almost roll back the whole thing. I wonder if it is still worth the extra maintenance effort. Which I can understand if that is what you like to do. The dependencies setup in the Java ecosystem is broken in so many places. Many folks publishing to Maven Central don’t seem to understand the consequences of the dependency information they publish.
But of course you get all the reports here, because users do a Guava update and then something does not seem to work anymore that worked before.
For me issues like this show that what we did is right. Issues with metadata in other libraries are now revealed instead of silently hidden. But of course I also understand that many users won’t care about that.