Spike: Dependency Auto-resolution for Gradle - validate single Java version and built in gradle dependencies command

Problem to solve

The current Gemnasium analyzer supports Gradle projects with multiple Java and Gradle version combinations, creating significant maintenance overhead. The Gemnasium image bundles Gradle versions 6.9.4, 7.6.6, and 8.14.3, auto-selected based on Java version when no gradlew wrapper is present.

Similar to the Maven approach validated in #584580 (closed), we want to explore whether we can simplify Gradle dependency resolution by using the native gradle dependencies command with a single modern Java/Gradle version combination.

Proposal

Objective

Validate that the native gradle dependencies command can successfully generate dependency graphs for Gradle projects, and determine if a single modern Java LTS version (Java 21 or 25) with a recent Gradle version can cover the majority of use cases.

Hypothesis

Similar to Maven, we hypothesize that:

  1. The native gradle dependencies command can produce parseable output (ASCII on stdout) for dependency scanning
  2. A single modern Java/Gradle version combination can work for most Gradle projects since dependency resolution doesn't require compilation
  3. Projects using gradlew (Gradle Wrapper) should work regardless of the host Gradle version

Experiment Design

  1. Validate gradle dependencies command output
    • Test the native gradle dependencies command on various Gradle projects
    • Analyze the ASCII output format and determine parsing feasibility
    • Compare output completeness with current Gemnasium approach
  2. Test Matrix
    • Find public Gradle projects of substantial size/complexity
    • Test with projects originally targeting different Java versions (8, 11, 17, 21)
    • Test with projects using different Gradle versions (6.x, 7.x, 8.x)
    • Validate behavior with and without gradlew wrapper
  3. Java/Gradle Version Compatibility (support matrix here)
    • Test using Java 25 (or 21 as fallback) with latest Gradle
    • Validate that dependency resolution works for projects targeting older Java versions
    • Document any version-specific failures or limitations
  4. Parser Implementation Assessment
    • Evaluate effort to implement a parser for gradle dependencies ASCII output
    • Compare with existing Gemnasium Gradle plugin approach
  5. Java Runtime Image Selection Criteria
    • There are multiple Java runtime distributions available. The PoC should evaluate and document the rationale for image selection based on Distribution, image size, FIPS compliance and licenssing.

Test Commands

# Using official Gradle Docker image with Java 21/25
docker run -it --rm -v $(pwd):/project -w /project gradle:8-jdk21 \
  gradle dependencies --configuration runtimeClasspath

# Or with gradlew if present
docker run -it --rm -v $(pwd):/project -w /project eclipse-temurin:21 \
  ./gradlew dependencies --configuration runtimeClasspath

Current Gemnasium Gradle Support

Java Version Gradle Version Notes
8, 11 6.9.4 Auto-selected when no gradlew
17 7.6.6 Auto-selected when no gradlew
21 8.14.3 Non-FIPS image only

Success Criteria

  1. Validate gradle dependencies command produces complete dependency tree

Yes. This command produces complete ASCII tree with transitive dependencies.

  1. Determine effort estimate for implementing new parser for this output format (ASCII)

Estimated Effort: Medium (2-3 weeks)

Requirements:

  • Parse ASCII tree structure (+---, \---, |, indentation)
  • Extract group:artifact:version from each line
  • Build dependency graph from tree hierarchy

Complexity: Higher than JSON parsing (e.g., dependencies.lock) but manageable with regex patterns.

  1. Acceptable success rate (>95%?) across diverse Gradle projects with single Java/Gradle version

NO - Achieved 45% success rate with Java 17.

Blockers:

  • Gradle < 7.0 incompatible with Java 17 (15%)
  • Multi-module structure issues (20%)
  • Project maintenance problems (20%)

Conclusion: 95% not achievable with single Java version due to Gradle's version fragmentation.

  1. Document behavior with gradlew wrapper vs system Gradle

WITH gradlew: Projects specify their own Gradle version in the wrapper. The host only needs a compatible Java version to run it. This is reliable and recommended.

WITHOUT gradlew: Must use a system-provided Gradle version. This fails when projects use deprecated syntax or require different Gradle versions.

  1. Documented list of failure patterns and potential mitigations
Failure Pattern Count Mitigation
Old Gradle (< 7.0) incompatible with Java 17 3 Use Java 11 or the exact target version
Multi-module: no root runtimeClasspath 4 Run per-module: :module:dependencies
Missing gradle-wrapper.jar 1 require/suggest project fixes
Build exceptions/missing dependencies 4 require/suggest project fixes
  1. Recommendation on Java/Gradle version combination

Cannot recommend a single Java version as 45% success rate is too low for production use.

Alternative Approaches:

Option A: Tiered Java Version Selection

IF Gradle >= 8.0 → Use Java 21
ELSE IF Gradle >= 7.0 → Use Java 17
ELSE IF Gradle >= 6.0 → Use Java 11
ELSE → Exclude or require project updates

Option B: Maintain Current Approach

  • Keep multiple Gradle versions in analyzer images
  • Use project's gradlew wrapper with compatible Java version
  • This validated approach handles Gradle's version sensitivity better

Conclusion: Unlike Maven, Gradle's frequent breaking changes and tight Java version coupling make a single-version approach impractical. The current multi-version approach is justified.

Known Risks to Validate

Risk Mitigation Status
ASCII output parsing complexity Evaluate feasibility and risks To validate
Gradle version compatibility with older projects Test with gradlew wrapper To validate
Build script execution during dependency resolution Test with --no-build-cache and similar flags To validate
Multi-module project support Test with complex multi-module projects To validate
Custom configurations beyond runtimeClasspath Document configuration handling To validate
FIPS compatibility Check image availability To validate

Key Questions to Answer

  1. Does gradle dependencies require executing build scripts, or can it resolve dependencies without compilation (like Maven)?
  2. Can we use a single Gradle version for all projects, or do we need to rely on gradlew?
  3. What is the output format, and how complex is parsing compared to dependencies.lock JSON format?
  4. How does Gradle handle multi-module projects in the dependency output?

Expected Outcomes

If successful, this PoC will enable:

  • Simpler implementation: Use native Gradle command instead of custom plugins
  • Reduced maintenance: Single Java/Gradle version to maintain
  • Vanilla image usage: Use public Gradle images without custom builds
  • Consistent approach: Similar pattern to Maven dependency resolution

Related Issues

Outcomes

Java Version Selection

Recommendation: Java 17

  • Java 25: 5% success rate - not supported by Gradle < 9.1.0
  • Java 21: Would require Gradle 8.5+, reducing coverage
  • Java 17: 50% success rate - broadest compatibility (Gradle 7.0+)

Gradle Version Approach

Recommendation: gradlew-first with bundled fallback

Approach Success Rate
gradlew (wrapper) 50%
System Gradle 8 + Java 17 35%
Combined (gradlew → fallback) 65% (estimated)

Rationale: Projects using gradlew download their required Gradle version at runtime. Bundled Gradle serves only as fallback for projects without wrapper.

Current Implementation Validation

Testing confirmed current Gemnasium analyzer already achieves optimal coverage:

  • Gemnasium: 50% success rate
  • Java 17 gradlew: 50% success rate (identical)
  • Same projects succeed/fail in both approaches

Conclusion: Current implementation strategy (gradlew-first, multi-version fallback) is correct.

Key Constraints

The 50% success rate ceiling is due to:

  • Gradle version incompatibilities (15% - Gradle < 7.0 incompatible with Java 17)
  • Multi-module structure issues (20% - root projects without dependencies)
  • Project maintenance issues (15% - missing files, broken configurations)

Unlike Maven (>95% success with single version), Gradle's tight version coupling and frequent API changes make higher success rates impractical without per-project version detection.

First Iteration Recommendation

Use single runtime environment with minimal bundling:

  • Image: Java 17 + git + curl + Gradle 8 (single version for fallback)
  • Strategy: Run gradlew if present, fallback to bundled Gradle 8 if no wrapper
  • Air-gapped: Require pre-populated Gradle cache or internal mirrors

Multi-version support and detection deferred to future iterations

Edited by Zamir Martins