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]

Reply via email to