Skip to content

Include jakarta.servlet-api in CLI runtime classpath#15392

Merged
jamesfredley merged 1 commit intoapache:7.0.xfrom
jamesfredley:fix/grails-cli-servlet-classpath
Feb 18, 2026
Merged

Include jakarta.servlet-api in CLI runtime classpath#15392
jamesfredley merged 1 commit intoapache:7.0.xfrom
jamesfredley:fix/grails-cli-servlet-classpath

Conversation

@jamesfredley
Copy link
Contributor

Summary

  • Fix NoClassDefFoundError for jakarta/servlet/ServletRequest when grailsw compiles custom scripts in src/main/scripts/

Problem

The grails-cli shadow JAR bundles grails-web-common (which registers HttpServletRequestExtension as a Groovy extension module), but jakarta.servlet-api is declared as compileOnly in grails-shell-cli. This means the servlet API classes are excluded from the fat JAR.

When the CLI's GroovyScriptCommandFactory compiles custom command scripts, the Groovy compiler auto-discovers the HttpServletRequestExtension from the fat JAR's classpath. Initializing this extension requires jakarta.servlet.ServletRequest, which is missing — causing all grailsw commands to fail when custom scripts exist in src/main/scripts/.

Fix

Change jakarta.servlet-api from compileOnly to implementation in grails-shell-cli/build.gradle so it is included in the shadow JAR's runtime classpath.

Reproduction

  1. Create a Grails 7 project with any custom script in src/main/scripts/
  2. Run ./grailsw dbm-gorm-diff (or any grailsw command)
  3. Observe: Failed to compile <script>.groovy: Unable to configure org.grails.web.mime.HttpServletRequestExtension due to missing dependency jakarta/servlet/ServletRequest

The grails-cli shadow JAR bundles grails-web-common (which registers
HttpServletRequestExtension as a Groovy extension module) but excluded
jakarta.servlet-api since it was declared compileOnly. This caused
NoClassDefFoundError for jakarta/servlet/ServletRequest when the CLI
compiled custom scripts in src/main/scripts/.

Change compileOnly to implementation so the servlet API is included
in the shadow JAR and available to the GroovyClassLoader at runtime.
@jamesfredley jamesfredley moved this to In Progress in Apache Grails Feb 16, 2026
@jamesfredley jamesfredley added this to the grails:7.0.8 milestone Feb 16, 2026
@jamesfredley jamesfredley self-assigned this Feb 16, 2026
@jdaugherty
Copy link
Contributor

Why not just exclude the extension when the shadow jar is built?

@jamesfredley
Copy link
Contributor Author

It appears to be required for create-controller, create-domain-class, generate-all, create-service, scaffolding, GSP/view generation, URL mappings, etc.) need to parse, understand, and generate code that uses Grails web-layer concepts

Copy link
Contributor

@jdaugherty jdaugherty left a comment

Choose a reason for hiding this comment

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

I think this is the right solution then, if @matrei agrees, we can merge.

@jamesfredley jamesfredley merged commit 4ada477 into apache:7.0.x Feb 18, 2026
32 checks passed
@jamesfredley jamesfredley deleted the fix/grails-cli-servlet-classpath branch February 18, 2026 19:46
@github-project-automation github-project-automation bot moved this from In Progress to Done in Apache Grails Feb 18, 2026
@matrei
Copy link
Contributor

matrei commented Feb 19, 2026

LGTM

jamesfredley added a commit that referenced this pull request Feb 19, 2026
…n scope

Document the rationale for the compileOnly-to-implementation change from PR #15392. The servlet API must be on the shadow JAR runtime classpath because grails-web-common's HttpServletRequestExtension is auto-discovered during script compilation, and CLI commands that generate web-layer code also depend on it.

Assisted-by: Claude Code <Claude@Claude.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants