matrei commented on PR #16184: URL: https://github.com/apache/grails-core/pull/16184#issuecomment-5661121239
Follow-up on 76bfb3bd08, found while running the example with `bootRun`: the error page of a standalone application does not render. ### Bug: any error or 404 in a standalone application ends in `Circular view path [error]` Open `http://localhost:8080/error` or any unmapped path in a browser and the response is Tomcat's own 500/404 page, with this in the log: ``` jakarta.servlet.ServletException: Circular view path [error]: would dispatch back to the current handler URL [/error] again. Check your ViewResolver setup! ``` Reproduced in the example with a `@SpringBootTest` on a random port sending `Accept: text/html` (a client sending no `Accept` gets Boot's JSON error body, which is why the example's tests do not see it). The view resolvers in the example's context, in the order the dispatcher consults them: | bean | class | order | |---|---|---| | `gspViewResolver` | `GrailsSiteMeshViewResolver` | `LOWEST_PRECEDENCE - 20` | | `beanNameViewResolver` | `BeanNameViewResolver` | `LOWEST_PRECEDENCE - 10` | | `mvcViewResolver`, `defaultViewResolver` | `ViewResolverComposite`, `InternalResourceViewResolver` | `LOWEST_PRECEDENCE` | `BasicErrorController.errorHtml` falls back to the view name `error`, which Boot serves from its whitelabel `error` bean through `BeanNameViewResolver`. The GSP resolver is asked first. There is no `error.gsp`, and `spring.gsp.jspEnabled` defaults to `true` (`GspAutoConfiguration.java:108`, applied at line 290), so `GroovyPageViewResolver.createFallbackView` (`GroovyPageViewResolver.java:258-273`) returns a JSTL view for `/error` without checking that any such JSP exists. That view forwards to `/error`, the URL being handled, and the servlet container rejects the loop. Boot's whitelabel page is never reached. `GroovyPageViewResolver` itself is untouched by this PR (`grails-web-gsp` has no diff against 8.0.x); what the PR changes is that the standalone module now starts, so this is the first time the path is reachable. A Grails application never hits it because its errors are routed by `UrlMappings`, not by `BasicErrorController`. Two things I checked before suggesting a fix: - `spring.gsp.jspEnabled=false` makes `/error` and 404s render the whitelabel page, and `form.jsp` still renders through Boot's `defaultViewResolver` - but undecorated: the `<meta name="layout" content="main"/>` in `form.jsp` is honoured only when the JSP is served through the GSP resolver's fallback, which the SiteMesh view resolver wraps. So flipping the default is not free for the example's JSP demonstration. - Adding `templates/error.gsp` to the example would make the page render, but only hides the module defect: every other standalone application without one gets the container's raw error page instead of Boot's. Suggested fix, in the module: have the JSP fallback resolve only a JSP that exists. `createJstlView` can ask `servletContext.getResource(url)` (the example's `JspSupport.canServeJsp` does exactly this) and return `null` otherwise, which lets resolution continue to `BeanNameViewResolver` and the whitelabel `error` bean, or to Boot's `defaultViewResolver` for a real JSP. That keeps JSP decoration in the example and fixes the error page for every consumer. A test in the example - `GET /does-not-exist` with `Accept: text/html` is a 404 whose body is the whitelabel page (or an `error.gsp` if you add one to show it off) - would pin it. A longer-term item, not for this PR: Boot resolves `error/404`, `error/5xx` templates through `TemplateAvailabilityProvider`s, and there is none for `.gsp`, so a standalone application cannot use per-status GSP error pages the way a Thymeleaf one can. -- 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]
