Skip to content

Conversation

lmcrean
Copy link
Contributor

@lmcrean lmcrean commented Sep 14, 2025

fixes #6666

Problem

Users can accidentally include duplicate Guava artifacts (guava-jdk5, guava-base, sisu-guava, etc.) alongside the main Guava library, causing classpath conflicts and runtime issues that are difficult to debug.

Solution

Declare that Guava provides the capabilities of known duplicate artifacts in module.json, following the existing google-collections pattern. This enables Gradle to detect and report conflicts at build time.

Changes

  • Added capability declarations for 5 duplicate Guava artifacts in all 4 variant sections of module.json:
    • com.google.guava:guava-base
    • com.google.guava:guava-jdk5
    • org.sonatype.sisu:sisu-guava
    • org.hudsonci.lib.guava:guava
    • org.apache.servicemix.bundles:org.apache.servicemix.bundles.guava

Testing

# Build and install locally with module metadata
./mvnw install -pl guava -DskipTests -q

# Verify module metadata contains capability declarations
grep -E "(guava-base|guava-jdk5|sisu-guava|hudsonci|servicemix)" \
  ~/.m2/repository/com/google/guava/guava/999.0.0-HEAD-jre-SNAPSHOT/guava-999.0.0-HEAD-jre-SNAPSHOT.module
# Expected: 24 lines (3 artifacts × 4 = 12, hudsonci × 4 = 4, servicemix × 8 = 8)

# For Gradle users - test conflict detection after release
# Note: This will only show conflicts once the changes are in a released version
# The SNAPSHOT version may not resolve correctly from mavenLocal()
mkdir test-guava-conflict && cd test-guava-conflict
cat > build.gradle << 'EOF'
plugins { id 'java' }
repositories { mavenCentral() }
dependencies {
    implementation 'com.google.guava:guava:NEXT_RELEASE_VERSION'
    implementation 'com.google.guava:guava-jdk5:17.0'
}
EOF
gradle dependencies --configuration compileClasspath
# Expected after release: Capability conflict error
# Current behavior (without these changes): Both dependencies resolve without conflict

Breaking Changes

Builds that currently (incorrectly) include both Guava and duplicate artifacts will now fail with a capability conflict error. Users must resolve by excluding the duplicate artifact or using Gradle's capability resolution.

Why this breaking change is necessary:

  • Prevents silent runtime failures (NoSuchMethodError, ClassNotFoundException)
  • Having duplicate Guava classes leads to unpredictable classloading behavior
  • Build-time failure is preferable to production runtime failure
  • Follows the established pattern already used for google-collections
  • Simple fix: exclude the duplicate or explicitly choose which one to use
  • "Fail fast, fail loud, fail at build time - not in production"

This update introduces several new Guava-related dependencies in the module.json file, including guava-base, guava-jdk5, sisu-guava, and others. These additions enhance the project's support for Guava libraries.

RELNOTES=n/a
@cpovirk cpovirk self-assigned this Sep 14, 2025
copybara-service bot pushed a commit that referenced this pull request Sep 14, 2025
Fixes #7990
Fixes #6666

RELNOTES=n/a
PiperOrigin-RevId: 806974529
@cpovirk
Copy link
Member

cpovirk commented Sep 14, 2025

Thanks. I took the liberty of pulling some more items from #6666 in #7991. (Because of the specifics of how our process works, we always submit an internal CL, which generates a new GitHub PR, but it still gets attributed to the original contributor.) If you don't want your name to show up on the additions there, let me know, and I can add them in a separate change.

@cpovirk
Copy link
Member

cpovirk commented Sep 15, 2025

Huh, somehow this breaks the Gradle integration test:

> Task :androidAndroidConstraintCompileClasspathJava:testClasspath FAILED
 
FAILURE: Build failed with an exception.
 
* What went wrong:
Execution failed for task ':androidAndroidConstraintCompileClasspathJava:testClasspath'.
> Could not resolve all files for configuration ':androidAndroidConstraintCompileClasspathJava:compileClasspath'.
   > Could not resolve com.google.collections:google-collections:1.0.
     Required by:
         project :androidAndroidConstraintCompileClasspathJava
      > Module 'com.google.guava:guava' has been rejected:
           Cannot select module with conflict on capability 'org.apache.servicemix.bundles:org.apache.servicemix.bundles.guava:999.0.0-HEAD-android-SNAPSHOT' also provided by [com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT(jreApiElements), com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT(androidApiElements)]
   > Could not resolve com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT.
     Required by:
         project :androidAndroidConstraintCompileClasspathJava
      > Module 'com.google.guava:guava' has been rejected:
           Cannot select module with conflict on capability 'org.apache.servicemix.bundles:org.apache.servicemix.bundles.guava:999.0.0-HEAD-android-SNAPSHOT' also provided by [com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT(jreApiElements), com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT(androidApiElements)]
   > Could not resolve com.google.guava:guava.
     Required by:
         project :androidAndroidConstraintCompileClasspathJava
      > Module 'com.google.guava:guava' has been rejected:
           Cannot select module with conflict on capability 'org.apache.servicemix.bundles:org.apache.servicemix.bundles.guava:999.0.0-HEAD-android-SNAPSHOT' also provided by [com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT(jreApiElements), com.google.guava:guava:999.0.0-HEAD-android-SNAPSHOT(androidApiElements)]

Any theories?

@cpovirk
Copy link
Member

cpovirk commented Sep 15, 2025

Sorry, I forgot to say:

That's https://github.com/google/guava/blob/master/util/gradle_integration_tests.sh. You might need to set JAVA_HOME to JDK11 or at least some version close to that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Look for other Maven artifacts that contain Guava classes, and list them in our metadata
2 participants