jamesfredley opened a new issue, #16129:
URL: https://github.com/apache/grails-core/issues/16129
## Description
`GrailsExceptionResolver` can mask the original application exception when
Spring's `RequestContextHolder` contains a plain `ServletRequestAttributes`
rather than a `GrailsWebRequest`.
During status-code mapping, `AbstractUrlMappingInfo.evaluateNameForValue`
unconditionally casts the current request attributes to `GrailsWebRequest`. The
resulting `ClassCastException` replaces the original exception and does not
preserve it as a cause.
## Reproduction
Using the official Grails `8.0.0-M5` distribution, bind a plain
`ServletRequestAttributes` and call the public exception resolver with an
explicit application exception:
```groovy
RequestContextHolder.setRequestAttributes(
new ServletRequestAttributes(new MockHttpServletRequest(), new
MockHttpServletResponse())
)
def original = new IllegalStateException('ORIGINAL_EXCEPTION')
exceptionResolver.resolveException(request, response, null, original)
```
A full Spring `MockMvc` dispatch also reproduces the condition because
MockMvc binds `ServletRequestAttributes`. Grails encounters an earlier
handler-lookup error, then replaces that error with the same cast failure while
resolving it.
## Actual behavior
```text
java.lang.ClassCastException: class
org.springframework.web.context.request.ServletRequestAttributes cannot be cast
to class org.grails.web.servlet.mvc.GrailsWebRequest
at
org.grails.web.mapping.AbstractUrlMappingInfo.evaluateNameForValue(AbstractUrlMappingInfo.java:124)
at
org.grails.web.mapping.DefaultUrlMappingInfo.getNamespace(DefaultUrlMappingInfo.java:189)
at
org.grails.web.mapping.mvc.AbstractGrailsControllerUrlMappings.collectControllerMapping(AbstractGrailsControllerUrlMappings.groovy:267)
at
org.grails.web.mapping.mvc.AbstractGrailsControllerUrlMappings.matchStatusCode(AbstractGrailsControllerUrlMappings.groovy:145)
at
org.grails.web.errors.GrailsExceptionResolver.matchStatusCode(GrailsExceptionResolver.java:267)
at
org.grails.web.errors.GrailsExceptionResolver.resolveViewOrForward(GrailsExceptionResolver.java:196)
at
org.grails.web.errors.GrailsExceptionResolver.resolveException(GrailsExceptionResolver.java:113)
```
The `ClassCastException` has no cause, so the original
`IllegalStateException("ORIGINAL_EXCEPTION")` is lost.
## Expected behavior
Exception resolution should not assume every `RequestAttributes`
implementation is a `GrailsWebRequest`. It should preserve and resolve the
original exception, or safely treat Grails-specific URL mapping values as
unavailable when the current attributes are not a `GrailsWebRequest`.
## Environment
- Grails: `8.0.0-M5`
- Groovy: `5.0.8`
- Spring Framework: `7.0.8`
- Spring Boot: `4.1.0`
- Java: `21.0.11`
The isolated application build passed with both reproduction tests,
including the full MockMvc path and direct public resolver path.
--
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]