jamesfredley commented on PR #15541:
URL: https://github.com/apache/grails-core/pull/15541#issuecomment-4200435788
## JSP GrailsLayoutSpec Investigation - Root Cause Analysis
### The Failure
The `"jsp demo"` test in `GrailsLayoutSpec` fails because the response is a
completely empty HTML page (`<html><head></head><body></body></html>`). All 37
other tests in the same spec pass (GSP-based views work fine).
### What Works
1. Jasper initializes correctly - TLD scanning runs at startup
2. The `GroovyPageViewResolver` correctly falls back to JSP when no GSP is
found:
```
Locating GSP view for controller DemoController and path /demo/hello
No GSP view found, falling back to locating JSTL view for name
[/demo/hello]
```
3. The `JstlView` forwards to the correct path:
```
Forwarding to [/WEB-INF/grails-app/views/demo/hello.jsp]
```
4. The JSP compiles successfully via JDT:
```
Compiled [.../hello_jsp.java] 773ms
```
### What Fails
After JSP compilation and execution, the response body is empty. Even after
removing the `<meta name="layout">` tag from the JSP (eliminating SiteMesh
decoration entirely), the response remains empty. The JSP content is never
captured.
### Root Cause
The issue is in `grails-layout`'s response buffering pipeline. The rendering
chain is:
1. `EmbeddedGrailsLayoutView.renderTemplate()` calls `obtainContent()`
2. `obtainContent()` creates a `GrailsContentBufferingResponse` wrapper and
calls `innerView.render(model, request, contentBufferingResponse)`
3. The `JstlView.render()` does a `RequestDispatcher.forward()` to the JSP,
writing to the wrapped response
4. `GrailsContentBufferingResponse.getContent()` tries to retrieve the
captured content
In step 4, `getContent()` returns `null`, causing the entire response to be
silently dropped. This is likely because `GrailsPageResponseWrapper` (from
SiteMesh 2.6.x) doesn't correctly capture output from Tomcat 11's forward
dispatch. Tomcat 11 (Jakarta Servlet 6.1) may have changed how
`RequestDispatcher.forward()` interacts with response wrappers, specifically
around `getOutputStream()` vs `getWriter()` delegation, or response buffer
commit semantics.
### Why GSP Works But JSP Doesn't
GSP views write directly to the `GrailsContentBufferingResponse` via
`GroovyPageView`, which uses `GSPGrailsLayoutPage` (captured at line 90-93 of
`GrailsContentBufferingResponse.getContent()`). JSP views go through a
`RequestDispatcher.forward()` which writes to the underlying
`GrailsPageResponseWrapper` (captured at line 95-98). The forward dispatch path
is what breaks in Tomcat 11.
### Fix Required
This needs a fix in `grails-layout`'s `GrailsPageResponseWrapper` or
`GrailsContentBufferingResponse` to properly capture content written during a
`RequestDispatcher.forward()` on Tomcat 11 / Jakarta Servlet 6.1. The fix
should be tracked as a separate issue since it's a `grails-layout` module bug,
not a configuration problem.
### Impact
Only JSP view rendering through the Grails layout pipeline is affected. Pure
GSP views, REST responses, and direct `render text:` calls all work correctly.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]