Remove the hardcoded servlet API dependency from gspCompile - #16068
Conversation
GroovyPagePlugin declared jakarta.servlet:jakarta.servlet-api:6.0.0 on the gspCompile configuration it registers. The dependency is redundant: the servlet API reaches the compile classpath transitively wherever GSPs can compile at all - grails-web-gsp exposes grails-web-taglib via api, and grails-web-taglib exposes jakarta.servlet-api via compileOnlyApi (grails-console contributes a second api route in apps). Since compiling a GSP definitionally requires the grails-gsp artifacts on the classpath, the servlet API always tags along, BOM-versioned (spring-boot-dependencies -> 6.1.0 today) with jakarta-servlet.version property overrides applying via BomPropertyOverridesPlugin. The hardcoded version had also drifted (6.0.0 vs the 6.1.0 the Spring Boot 4 BOM manages) and registered an explicitly-versioned dependency that version-scanning tooling reports as if the build had declared it, which is how this was noticed. Empirically verified: a bare Grails plugin project (grails-plugin + grails-gsp plugins, one GSP using params/request/session and g: taglibs, no servlet-api declaration anywhere) compiles its GSPs successfully against published 8.0.0-M4 artifacts with this dependency deleted; dependencyInsight confirms the transitive routes above and gspCompile resolves empty. The gspCompile configuration is kept as an extension point for additional GSP-compile-only dependencies.
2fa647e to
aba633b
Compare
|
I'm ok to merge this if @matrei is. I think he had been making changes to not rely on transitive dependencies. GSP's project structure is odd to me though so maybe it's explicit due it's split. I want his approval to merge this. |
|
@jdaugherty @codeconsole We can remove it, but we should also add it to We should also add a comment in the |
Addresses review feedback on the gspCompile servlet-api removal.
grails-web-gsp uses jakarta.servlet types throughout its own public API
(GroovyPageView, PageRenderer, GroovyPagesServlet, GSPResponseWriter,
NullView, GroovyPageViewResolver) but declared no servlet-api dependency:
it compiled only because grails-web-taglib re-exports one via
compileOnlyApi, reached through the api project(':grails-web-taglib')
edge. Consumers that exclude grails-web-taglib would lose the servlet API
from the GSP compile classpath. Declare compileOnlyApi
'jakarta.servlet:jakarta.servlet-api' on grails-web-gsp directly so the
module stands on its own; the version stays BOM-managed (6.1.0), and the
generated POM now exports it from grails-web-gsp itself.
Also document the gspCompile configuration at its registration site: it
is appended to the GSP compile classpath alongside compileClasspath, so
applications can use it for classes referenced from GSPs but absent from
their own compile classpath. It is empty by default now that the
hardcoded servlet-api entry is gone.
Verified with :grails-web-gsp:build, :grails-web-taglib:build,
validateDependencyVersions on both, :grails-gradle-plugins:check, and
builds of every in-repo consumer of grails-web-gsp.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 8.0.x #16068 +/- ##
==================================================
- Coverage 51.9800% 51.9586% -0.0214%
+ Complexity 18035 18027 -8
==================================================
Files 2038 2038
Lines 95708 95707 -1
Branches 16648 16648
==================================================
- Hits 49749 49728 -21
- Misses 38622 38643 +21
+ Partials 7337 7336 -1
🚀 New features to boost your workflow:
|
✅ All tests passed ✅🏷️ Commit: ea59fc5 Learn more about TestLens at testlens.app. |
Follow-up to #16068, which removed the hardcoded servlet API dependency that gspCompile carried. The configuration was introduced in 2014 as the classpath for the original Ant-based GSP compiler, which ran via IsolatedAntBuilder: antBuilder.withClasspath(project.configurations.gspCompile) It held the two artifacts that compiler needed - grails-web-gsp and the servlet API. When GSP compilation moved to the forked GroovyPageForkCompileTask, whose classpath is compileClasspath + gspCompile + compiled classes + providedCompile, the grails-web-gsp entry was dropped and only the servlet API line remained. #16068 removed that, leaving a configuration that is empty for every build and contributes no files to the GSP compile classpath. GSPs continue to compile against compileClasspath, the project's compiled classes and providedCompile, which is what actually supplies everything GSP compilation needs. This is a behavior break for any build that declares dependencies on gspCompile: those fail with "Could not find method gspCompile()". Documented in the Grails 8 upgrade guide with the migration to compileOnly, which lands on the same compile classpath. Adds GroovyPagePluginFunctionalSpec, a TestKit spec that applies org.apache.grails.gradle.grails-gsp and asserts the configuration is gone while compileGroovyPages and compileWebappGroovyPages still resolve the compile classpath, provided dependencies and compiled classes. Verified the first assertion fails when the configuration is restored. Verified with :grails-gradle-plugins:test --rerun-tasks (90 tests), :grails-gradle-plugins:check, aggregateViolations (Checkstyle, CodeNarc, PMD, SpotBugs all clean) and :grails-doc:publishGuide.
What
GroovyPagePlugindeclaredjakarta.servlet:jakarta.servlet-api:6.0.0on thegspCompileconfiguration it registers. This PR removes the dependency entirely. ThegspCompileconfiguration is kept as an extension point for additional GSP-compile-only dependencies; empty, it resolves trivially.Why it's redundant
The servlet API already reaches the compile classpath transitively wherever GSPs can compile at all:
grails-web-gspexposesgrails-web-taglibviaapigrails-web-taglibexposesjakarta.servlet:jakarta.servlet-apiviacompileOnlyApi(needed for theTagLibrarytrait)grails-consolecontributes a second route via a plainapidependency in apps)Since compiling a GSP definitionally requires the grails-gsp artifacts on the classpath, the servlet API always tags along — BOM-versioned (
spring-boot-dependencies→ 6.1.0 today), withjakarta-servlet.versionproperty overrides working viaBomPropertyOverridesPlugin.Empirical verification
A bare Grails plugin project —
groovy+grails-plugin+grails-gspplugins,implementation 'org.apache.grails:grails-gsp'+grails-web-boot, one GSP exercisingparams/request/sessionandg:each/g:link/g:form, no servlet-api declaration anywhere — compiles its GSPs successfully against published 8.0.0-M4 artifacts with this dependency deleted.dependencyInsightconfirmsjakarta.servlet-api:6.1.0arrives oncompileClasspathpurely via the transitive routes above, and thegspCompileconfiguration resolves empty.Why the hardcode was worth removing
grails { bom = null }and standalone-grails-gspcases need nothing: there is no version to supply and nothing to resolve.Verified with
:grails-gradle-plugins:compileGroovyand:grails-gradle-plugins:test, plus the external probe project above.