Skip to content

feat: Replace Spring Dependency Management plugin with Gradle platform + lightweight BOM property overrides#15467

Open
jamesfredley wants to merge 3 commits into8.0.xfrom
feat/gradle-managed-version-overrides
Open

feat: Replace Spring Dependency Management plugin with Gradle platform + lightweight BOM property overrides#15467
jamesfredley wants to merge 3 commits into8.0.xfrom
feat/gradle-managed-version-overrides

Conversation

@jamesfredley
Copy link
Contributor

@jamesfredley jamesfredley commented Feb 26, 2026

Summary

This is a potential solution for standardizing Grails on Gradle's native platform() dependency management - the modern, recommended approach - while preserving the one feature that Gradle platforms currently lack: property-based version overrides from BOMs.

The Spring Dependency Management plugin served Grails well, but it duplicates significant Gradle functionality (dependency resolution, exclusions, BOM imports) and introduces behavioral differences from standard Gradle resolution. Gradle platforms now handle the vast majority of what the Spring DM plugin provided. The one gap is the ability to override BOM-managed versions via project properties (e.g., ext['slf4j.version'] = '2.0.9' or entries in gradle.properties).

This PR bridges that gap with a lightweight ~350-line utility (BomManagedVersions) so Grails can remove the Spring DM plugin entirely.

What This Changes

Core: BomManagedVersions.groovy (new)

A lightweight utility that:

  1. Resolves the BOM POM via a detached Gradle configuration (using the @pom artifact notation)
  2. Parses the POM XML using JDK's built-in DocumentBuilderFactory - no external dependencies
  3. Extracts the <properties> block and <dependencyManagement> entries, building a mapping of property names to the artifacts they control
  4. Recursively follows <scope>import</scope> BOM imports (e.g., grails-bom imports spring-boot-dependencies)
  5. Applies overrides via Configuration.resolutionStrategy.eachDependency() - only for properties where project.hasProperty(name) is true (covering both ext['...'] and gradle.properties)

Plugin: GrailsGradlePlugin.groovy (modified)

  • Replaced applySpringDependencyManagementPlugin() with applyGrailsBom()
  • New method uses project.dependencies.platform(bomCoordinates) for base BOM import
  • Calls BomManagedVersions.resolve() to enable property-based overrides
  • Spring DM plugin is no longer applied or referenced

Extension: GrailsExtension.groovy (modified)

  • The springDependencyManagement flag is deprecated with a message directing users to Gradle's native platform support
  • Flag is retained for backwards compatibility but has no effect

Build: plugins/build.gradle (modified)

  • Removed implementation 'io.spring.gradle:dependency-management-plugin' dependency

Examples & Docs

  • Removed io.spring.dependency-management plugin from example projects (gsp-spring-boot, graphql spring-boot-app)
  • Updated gradleDependencies.adoc to document the Gradle platform approach and property override mechanism
  • Updated comments in grailsCentralPublishing.gradle template and grails-bom/build.gradle

How Version Overrides Work

The mechanism is intentionally simple and mirrors exactly what the Spring DM plugin provided:

// In build.gradle
ext['slf4j.version'] = '2.0.9'

// Or in gradle.properties
slf4j.version=2.0.9

BomManagedVersions reads the BOM's <properties> to discover that slf4j.version controls org.slf4j:slf4j-api (and other slf4j artifacts), then uses eachDependency to force the override at resolution time.

Why Not Just Use Gradle Platforms?

Gradle platforms (platform()) handle:

  • ✅ BOM import and version alignment
  • ✅ Transitive dependency management
  • ✅ Dependency exclusions (via standard Gradle mechanisms)
  • ✅ Version constraints and conflict resolution

Gradle platforms do not handle:

  • ❌ Reading <properties> from BOM POMs and allowing project-level overrides (Gradle issue #9160 - confirmed "very unlikely" to be implemented)

This is the specific gap BomManagedVersions fills.

Testing

  • Unit tests (BomManagedVersionsSpec): 4 tests covering POM parsing, property extraction, nested BOM imports, and property-to-artifact mapping
  • Functional test (BomPlatformFunctionalSpec): End-to-end Gradle TestKit test verifying that gradle.properties overrides are applied during dependency resolution
  • All 17 existing + new tests pass: BUILD SUCCESSFUL

Known Follow-up Items

  • build-logic/docs-core/ExtractDependenciesTask.groovy still uses Spring DM's shaded Maven model classes (io.spring.gradle.dependencymanagement.org.apache.maven.model.Model) for POM reading at build time. This should be migrated to JDK XML parsing in a separate follow-up.
  • Verify compatibility once the Gradle 9.3.1 upgrade PR merges (separate effort).
  • Verify the Forge/CLI project generators don't include Spring DM in generated projects.

Motivation

Standardizing on Gradle platforms is the direction the Gradle ecosystem is heading. The Spring DM plugin, while feature-rich, introduces a parallel dependency resolution system that can conflict with Gradle's native behavior. By removing it and adding only the minimal property-override bridge, Grails 8 gets:

  1. Simpler dependency resolution - one system (Gradle) instead of two (Gradle + Spring DM)
  2. Better Gradle compatibility - no more Spring DM vs Gradle resolution conflicts
  3. Preserved developer experience - ext['version.property'] and gradle.properties overrides continue to work exactly as before
  4. Smaller plugin footprint - ~350 lines of Groovy with zero external dependencies vs the full Spring DM plugin

Related:

spring-gradle-plugins/dependency-management-plugin#211
gradle/gradle#9160

…m and lightweight BOM property overrides

Replace the Spring Dependency Management Gradle plugin with Gradle's
native platform() support plus a lightweight BomManagedVersions utility
that preserves the ability to override BOM-managed dependency versions
via project properties (ext[] or gradle.properties).

This allows Grails to standardize on Gradle platforms - the modern
dependency management solution - while retaining the one feature
Gradle platforms lack: property-based version overrides from BOMs.

Changes:
- Add BomManagedVersions: parses BOM POM XML to extract property-to-
  artifact mappings, applies version overrides via eachDependency()
- Update GrailsGradlePlugin to use platform() + BomManagedVersions
  instead of Spring DM plugin
- Deprecate GrailsExtension.springDependencyManagement flag
- Remove Spring DM plugin from plugins/build.gradle dependency
- Remove Spring DM plugin from example projects
- Update documentation to reflect Gradle platform approach
- Add unit tests (BomManagedVersionsSpec) and functional test
  (BomPlatformFunctionalSpec)

Note: build-logic/docs-core/ExtractDependenciesTask still uses Spring
DM's shaded Maven model classes and should be addressed in a follow-up.

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley jamesfredley self-assigned this Feb 26, 2026
@jamesfredley jamesfredley marked this pull request as ready for review February 26, 2026 16:30
Copilot AI review requested due to automatic review settings February 26, 2026 16:30
@jamesfredley jamesfredley added this to the grails:8.0.0-M1 milestone Feb 26, 2026
@jamesfredley jamesfredley added the relates-to:v8 Grails 8 label Feb 26, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the Spring Dependency Management plugin with Gradle's native platform() mechanism and introduces a lightweight utility (BomManagedVersions) to enable property-based version overrides from BOMs—the one feature Gradle platforms don't natively support.

Changes:

  • Removed Spring Dependency Management plugin dependency and usage across the codebase
  • Added BomManagedVersions utility (~350 lines) to parse BOM POMs and apply property-based version overrides
  • Updated plugin to use platform() for BOM import instead of Spring DM's mavenBom()

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/BomManagedVersions.groovy New utility class that parses BOM POMs and enables property-based version overrides via Gradle's resolution strategy
grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsGradlePlugin.groovy Replaced Spring DM plugin application with native Gradle platform support plus BomManagedVersions
grails-gradle/plugins/src/main/groovy/org/grails/gradle/plugin/core/GrailsExtension.groovy Deprecated springDependencyManagement flag with guidance on new approach
grails-gradle/plugins/build.gradle Removed Spring DM plugin dependency
grails-test-examples/gsp-spring-boot/app/build.gradle Removed Spring DM plugin from example project
grails-data-graphql/examples/spring-boot-app/build.gradle Removed Spring DM plugin from example project
grails-doc/src/en/guide/commandLine/gradleBuild/gradleDependencies.adoc Updated documentation to reflect platform-based approach and property override mechanism
grails-profiles/plugin/templates/grailsCentralPublishing.gradle Updated comment to reflect new version management approach
grails-bom/build.gradle Updated comment about version property references
grails-gradle/plugins/src/test/groovy/org/grails/gradle/plugin/core/BomManagedVersionsSpec.groovy Unit tests for BOM parsing and property extraction
grails-gradle/plugins/src/test/groovy/org/grails/gradle/plugin/core/BomPlatformFunctionalSpec.groovy Functional test verifying platform integration
grails-gradle/plugins/src/test/resources/test-projects/bom-platform-basic/* Test project files for functional testing
grails-gradle/plugins/src/test/resources/test-poms/test-bom.pom Test BOM POM for unit tests

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

…h constant

Add factory.setXIncludeAware(false) for explicit XML security hardening
and extract magic number 10 to MAX_PROPERTY_INTERPOLATION_DEPTH constant.

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley jamesfredley force-pushed the feat/gradle-managed-version-overrides branch 2 times, most recently from eb85805 to 5643538 Compare February 26, 2026 20:42
The Spring Dependency Management plugin applied version constraints
globally to every configuration via configurations.all() and
resolutionStrategy.eachDependency(). With the switch to Gradle's native
platform(), version constraints must be added explicitly.

Apply the grails-bom platform to all declarable configurations using
configureEach, matching the previous global behavior. Non-declarable
configurations (apiElements, runtimeElements, etc.) inherit constraints
through their parent configurations. Code quality tool configurations
(checkstyle, codenarc, etc.) are excluded because platform() constraints
participate in version conflict resolution and can upgrade transitive
dependencies, breaking the tools. Also ensure the developmentOnly
configuration always exists via maybeCreate.

Assisted-by: Claude Code <Claude@Claude.ai>
@jamesfredley jamesfredley force-pushed the feat/gradle-managed-version-overrides branch from 5643538 to 5e89656 Compare February 26, 2026 20:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Standardize on Gradle Platforms or Spring Dependency Management Gradle Plugin for grails-bom application

2 participants