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:
- The native
gradle dependenciescommand can produce parseable output (ASCII on stdout) for dependency scanning - A single modern Java/Gradle version combination can work for most Gradle projects since dependency resolution doesn't require compilation
- Projects using
gradlew(Gradle Wrapper) should work regardless of the host Gradle version
Experiment Design
-
Validate
gradle dependenciescommand output- Test the native
gradle dependenciescommand on various Gradle projects - Analyze the ASCII output format and determine parsing feasibility
- Compare output completeness with current Gemnasium approach
- Test the native
-
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
gradlewwrapper
-
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
-
Parser Implementation Assessment
- Evaluate effort to implement a parser for
gradle dependenciesASCII output - Compare with existing Gemnasium Gradle plugin approach
- Evaluate effort to implement a parser for
-
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
- Validate
gradle dependenciescommand produces complete dependency tree
Yes. This command produces complete ASCII tree with transitive dependencies.
- 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:versionfrom each line - Build dependency graph from tree hierarchy
Complexity: Higher than JSON parsing (e.g., dependencies.lock) but manageable with regex patterns.
- 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.
- Document behavior with
gradlewwrapper 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.
- 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 |
- 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
- Does
gradle dependenciesrequire executing build scripts, or can it resolve dependencies without compilation (like Maven)? - Can we use a single Gradle version for all projects, or do we need to rely on
gradlew? - What is the output format, and how complex is parsing compared to dependencies.lock JSON format?
- 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
- Parent spike: #582607 (closed)
- Maven spike: #584580 (closed)
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