You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@grails.apache.org by "codeconsole (via GitHub)" <gi...@apache.org> on 2026/10/20 23:31:47 UTC
[I] Resolve Grails formats through Spring MVC's content negotiation [grails-core]
codeconsole opened a new issue, #16698:
URL: https://github.com/apache/grails-core/issues/16698
## Background
After #16237, two policies negotiate a response:
- **Grails' negotiation** picks the *format* that selects a renderer, a view or a `withFormat` block: `response.format`, `request.format` (from `Content-Type`), `withFormat` and the format `respond` writes in. It chooses among the types `grails.mime.types` configures, with rules of its own:
- the `Accept` header ignored for the user agents `grails.mime.disable.accept.header.userAgents` lists, and for XHR requests unless `grails.mime.disable.accept.header.userAgentsXhr` is set,
- `text/xml` and `application/xml` merged into `xml`, and `+xml` types preferred to it at equal quality,
- the problem types of RFC 9457 read as the `json` and `xml` formats,
- `params.format` and URL extensions, and the fallback to the first configured type.
- **Spring MVC's `ContentNegotiationManager`** picks the *media type* among those its message converters can write. Since #16237 it decides how Spring MVC writes problems, the values of actions it writes (a returned `ResponseEntity`, `ProblemDetail` and so on, and, with `grails.controllers.responseBody`, the values of `@ResponseBody` actions), and the JSON `respond` writes through Spring MVC.
The parsing is already shared: `DefaultAcceptHeaderParser` reads each media type with Spring's `MediaType.parseMediaType`, and the Grails data formats are registered with Spring as format aliases. What remains is the two policies, which can answer the same request differently. A browser's `*/*` is one example; a client of a Grails view and of a Spring-written value of the same action is another.
## Proposal
**Grails 10, opt-in.** Add a setting that resolves `request.format`, `response.format`, `withFormat` and `respond`'s format through Spring MVC's `ContentNegotiationManager`, mapping the media type it selects back to the Grails format `grails.mime.types` gives it. For each Grails rule above, decide whether to:
- keep it, as a strategy of Spring's manager that applies to Grails actions only,
- port it to Spring's configuration, such as `spring.mvc.contentnegotiation.*`, or
- drop it, with an entry in the upgrade guide.
**A comparison spec.** Run a matrix of requests through both policies and record every answer that differs. The matrix covers `Accept` headers with qualities, wildcards and `+json`/`+xml` types, browser and XHR user agents, `?format=` and URL extensions, `Content-Type` for `request.format`, and several `grails.mime.types` configurations. That record is the evidence for the default, and the list the upgrade guide gives.
**Grails 11, the default.** Decide whether the setting becomes the default when the legacy `respond` rendering is removed. By then every JSON and XML body goes through Spring MVC, and Grails' negotiation only picks views and `withFormat` blocks.
## Constraints
- `GrailsContentNegotiationStrategy` stays out of the context as a Spring `ContentNegotiationStrategy` bean, which Spring Security adopts.
- The negotiation of Spring MVC endpoints (`@RestController`, `produces`, `spring.mvc.contentnegotiation.*`) is unchanged.
- The Grails 9 behaviour stays the default until the setting's default changes, as for the other migration settings in `grails.config.Settings`.
--
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: notifications-unsubscribe@grails.apache.org.apache.org
For queries about this service, please contact Infrastructure at:
users@infra.apache.org