codeconsole commented on code in PR #16237:
URL: https://github.com/apache/grails-core/pull/16237#discussion_r4213527410
##########
grails-rest-transforms/src/main/groovy/org/grails/plugins/web/rest/render/DefaultRendererRegistry.groovy:
##########
@@ -77,13 +80,32 @@ class DefaultRendererRegistry extends
ClassAndMimeTypeRegistry<Renderer, Rendere
@Value('${grails.converters.encoding:UTF-8}')
String encoding = grails.util.GrailsWebUtil.DEFAULT_ENCODING
+ @Autowired(required = false)
+ SpringMessageConverters springMessageConverters
+
+ @Autowired(required = false)
+ GrailsJsonMapperCustomizer grailsJsonMapperCustomizer
+
+ @Autowired(required = false)
+ NamedJsonRenderer namedJsonRenderer
+
+ @Autowired(required = false)
+ ValidationProblemDetailFactory validationProblemDetailFactory
+
+ /**
+ * Whether JSON responses are written by Spring's message converters. When
unset, they are unless
+ * the application customized the legacy {@code grails.converters.JSON}
converter.
+ */
+ @Value('${grails.web.rendering.json.spring:#{null}}')
+ Boolean useSpringJson
Review Comment:
Added in be751d3846 and 4b2ae6733b:
`additional-spring-configuration-metadata.json` entries for
`grails.web.rendering.json.spring` (grails-rest-transforms),
`grails.databinding.json.jackson` (grails-web-databinding) and
`grails.web.rendering.xml.spring` (grails-xml), with the
`configuration-metadata` plugin applied. `generateConfigReference` now scans
those three modules (d1668dfa0e). Applying the plugin exposed a generator bug
with a constructor parameter named `metaClass`, fixed in 472bf0236c.
##########
grails-doc/src/en/guide/upgrading/upgrading90x.adoc:
##########
@@ -0,0 +1,289 @@
+////
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+////
+
+=== Upgrade Instructions for Grails and Related Dependencies
+
+This guide outlines the changes to review when you upgrade a Grails project
from Grails 8 to Grails 9.
+
+==== 1. XML Web Support Is Optional
+
+XML conversion, request-body binding, codecs, and REST renderers now live in
the optional
+`grails-xml` module. Newly generated applications and the web starter no
longer include that module by
+default. MIME type negotiation still recognizes `application/xml`, `text/xml`,
Atom, and other XML media
+types; recognizing a media type does not install an XML serializer.
+
+New REST controllers, RESTful controllers, resources, and scaffolded
controllers generated by the
+`rest-api` profile advertise JSON only. After adding `grails-xml`, add `xml`
to the artefact's
+`responseFormats` or `formats` declaration when that endpoint should negotiate
XML.
+
+Applications that expose XML endpoints or use `grails.converters.XML`, XML
object marshallers, XML data
+binding, or the XML and Atom renderers must add the module explicitly:
+
+[source,groovy]
+.build.gradle
+----
+dependencies {
+ implementation 'org.apache.grails:grails-xml'
+}
+----
+
+The module preserves the established Grails XML APIs and compatibility
marshalling for domain-shaped
+payloads, collections, maps, validation errors, named converter
configurations, and include/exclude
+projections.
+
+Ordinary bean responses can also be written by Spring Framework's
`JacksonXmlHttpMessageConverter`,
+backed by the Spring Boot-managed Jackson XML mapper. As in a plain Spring
Boot application, that
+converter is registered only when Jackson's XML dataformat is on the
classpath, so applications that
+want it add the dependency themselves:
+
+[source,groovy]
+.build.gradle
+----
+dependencies {
+ runtimeOnly 'tools.jackson.dataformat:jackson-dataformat-xml'
+}
+----
+
+Without it, `grails-xml` still renders XML through the Grails converter.
Applications may also register
+their own Spring XML message converter or OXM/JAXB infrastructure through
public Spring configuration
+APIs.
+
+This change does not affect Grails plugin descriptors. Plugin metadata
continues to be generated and
+published in its existing descriptor format; `grails-xml` concerns application
HTTP payloads only.
+
+==== 2. `respond()` Uses Spring JSON Conversion
+
+`respond()` now writes JSON through Spring MVC's message converters, backed by
Spring Boot's configured
+Jackson `JsonMapper`, instead of the legacy `grails.converters.JSON`
converter. Jackson can render date
+formats, bean properties, circular references, and validation errors
differently, so review the JSON
+returned by `respond()` endpoints when you upgrade. Explicit `render value as
JSON` calls still use the
+legacy converter.
+
+An application that customizes the legacy converter keeps it for `respond()`,
so that its output does not
+change silently. That is the case once the application, or one of its plugins,
registers a JSON object
+marshaller with `JSON.registerObjectMarshaller(...)` or
`JSON.withDefaultConfiguration(...)`, declares an
+`ObjectMarshallerRegisterer` or `JsonRenderer` bean, or sets
`grails.converters.json.default.deep` or
+`grails.converters.json.date: javascript`. The first such response logs a
warning. Marshaller registration
+is deprecated for removal (see the next section), so plan to replace those
marshallers with Jackson
+serializers.
+
+Set `grails.web.rendering.json.spring` to decide explicitly. `false` keeps the
legacy converter for
+`respond()` without the warning; `true` uses Spring's converters even while
legacy marshallers are
+registered, for example once Jackson serializers replace them for `respond()`
but `render ... as JSON`
+calls still rely on them:
+
+[source,yaml]
+.application.yml
+----
+grails:
+ web:
+ rendering:
+ json:
+ spring: false
+----
+
+Grails selects the first configured MVC `HttpMessageConverter` that can write
the
+response type and negotiated JSON media type and advertises a JSON media type
for that class
+(`application/json`, `text/json`, or a `+json` subtype). Generic `*/*` string
and byte-array converters
+are skipped, so strings remain JSON strings and byte arrays use Jackson's
base64 JSON representation.
+The same media-family rule applies to XML conversion; a generic text converter
cannot strip the XML
+string element.
+
+The standard Jackson converter uses an isolated mapper derived from Boot's
configured `JsonMapper`
+for Grails domain compatibility. Persistent properties, identifiers,
association identifiers, and
+per-response domain projections follow Grails metadata. On this domain path,
Jackson property
+annotations (`@JsonIgnore`, `@JsonProperty`, `@JsonInclude`, `@JsonView`,
`@JsonFormat`), property
+mixins, naming strategies, and transient getters do not define the
representation. Register an
+explicit serializer or return a DTO when that property model is required.
Ordinary non-domain beans
+retain Jackson's property rules. Application-provided converter subclasses and
per-type mapper
+registrations keep their configured behavior and precedence.
+
+Boot's shared mapper is not given the Grails domain serializer, so plain
Spring `@RestController`
+responses retain Jackson's normal domain property model. Both mappers
serialize Groovy `GString`
+values as strings. Both also serialize Spring `Errors` as an `errors` array
containing object, field,
+message, and codes, without rejected values; only Grails `respond errors`
adapts that array into an
+RFC 9457 problem response.
+
+Grails retains the legacy converter path when a named converter configuration
or per-response
+`includes`/`excludes` projection is requested, or when no configured MVC
converter can write the
+selected type and media type. Explicit application and plugin `Renderer` beans
continue to take
+precedence over the default renderer.
+
+Jackson conversion uses UTF-8 for intermediate bytes; the response writer
applies
+`grails.converters.encoding`, so non-UTF response encodings do not corrupt the
intermediate JSON.
+
+Controller unit tests use Boot's Jackson configuration and the same setting. A
test's `doWithSpring`
Review Comment:
The sentence now points at a nested `@Configuration` class and says the
deprecated `doWithSpring` runs too late (d1668dfa0e).
`ControllerJsonMapperOverrideSpec` 'a mapper bean from nested configuration
makes Boot back off' covers the mapper bean.
##########
grails-doc/src/en/guide/upgrading/upgrading90x.adoc:
##########
@@ -0,0 +1,289 @@
+////
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+////
+
+=== Upgrade Instructions for Grails and Related Dependencies
+
+This guide outlines the changes to review when you upgrade a Grails project
from Grails 8 to Grails 9.
+
+==== 1. XML Web Support Is Optional
+
+XML conversion, request-body binding, codecs, and REST renderers now live in
the optional
+`grails-xml` module. Newly generated applications and the web starter no
longer include that module by
+default. MIME type negotiation still recognizes `application/xml`, `text/xml`,
Atom, and other XML media
+types; recognizing a media type does not install an XML serializer.
+
+New REST controllers, RESTful controllers, resources, and scaffolded
controllers generated by the
+`rest-api` profile advertise JSON only. After adding `grails-xml`, add `xml`
to the artefact's
+`responseFormats` or `formats` declaration when that endpoint should negotiate
XML.
+
+Applications that expose XML endpoints or use `grails.converters.XML`, XML
object marshallers, XML data
Review Comment:
Done in d1668dfa0e. Each page you listed notes that XML needs `grails-xml`,
included by the Grails 9 web starter and an explicit dependency from Grails 10:
`domainResources.adoc`, `extendingRestfulController.adoc`, `hal.adoc`,
`versioningResources.adoc`, `openApi.adoc`, `contentNegotiation.adoc` and
`binding.adoc`. `objectMarshallers.adoc` names Grails 11 and no longer calls
marshaller registration deprecated (d81e3956db).
##########
grails-doc/src/en/guide/upgrading/upgrading90x.adoc:
##########
@@ -0,0 +1,289 @@
+////
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements. See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership. The ASF licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License. You may obtain a copy of the License at
+
+https://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing,
+software distributed under the License is distributed on an
+"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+KIND, either express or implied. See the License for the
+specific language governing permissions and limitations
+under the License.
+////
+
+=== Upgrade Instructions for Grails and Related Dependencies
+
+This guide outlines the changes to review when you upgrade a Grails project
from Grails 8 to Grails 9.
+
+==== 1. XML Web Support Is Optional
+
+XML conversion, request-body binding, codecs, and REST renderers now live in
the optional
+`grails-xml` module. Newly generated applications and the web starter no
longer include that module by
+default. MIME type negotiation still recognizes `application/xml`, `text/xml`,
Atom, and other XML media
+types; recognizing a media type does not install an XML serializer.
+
+New REST controllers, RESTful controllers, resources, and scaffolded
controllers generated by the
+`rest-api` profile advertise JSON only. After adding `grails-xml`, add `xml`
to the artefact's
+`responseFormats` or `formats` declaration when that endpoint should negotiate
XML.
+
+Applications that expose XML endpoints or use `grails.converters.XML`, XML
object marshallers, XML data
+binding, or the XML and Atom renderers must add the module explicitly:
+
+[source,groovy]
+.build.gradle
+----
+dependencies {
+ implementation 'org.apache.grails:grails-xml'
+}
+----
+
+The module preserves the established Grails XML APIs and compatibility
marshalling for domain-shaped
+payloads, collections, maps, validation errors, named converter
configurations, and include/exclude
+projections.
+
+Ordinary bean responses can also be written by Spring Framework's
`JacksonXmlHttpMessageConverter`,
+backed by the Spring Boot-managed Jackson XML mapper. As in a plain Spring
Boot application, that
+converter is registered only when Jackson's XML dataformat is on the
classpath, so applications that
+want it add the dependency themselves:
+
+[source,groovy]
+.build.gradle
+----
+dependencies {
+ runtimeOnly 'tools.jackson.dataformat:jackson-dataformat-xml'
+}
+----
+
+Without it, `grails-xml` still renders XML through the Grails converter.
Applications may also register
+their own Spring XML message converter or OXM/JAXB infrastructure through
public Spring configuration
+APIs.
+
+This change does not affect Grails plugin descriptors. Plugin metadata
continues to be generated and
+published in its existing descriptor format; `grails-xml` concerns application
HTTP payloads only.
+
+==== 2. `respond()` Uses Spring JSON Conversion
+
+`respond()` now writes JSON through Spring MVC's message converters, backed by
Spring Boot's configured
+Jackson `JsonMapper`, instead of the legacy `grails.converters.JSON`
converter. Jackson can render date
+formats, bean properties, circular references, and validation errors
differently, so review the JSON
+returned by `respond()` endpoints when you upgrade. Explicit `render value as
JSON` calls still use the
+legacy converter.
+
+An application that customizes the legacy converter keeps it for `respond()`,
so that its output does not
+change silently. That is the case once the application, or one of its plugins,
registers a JSON object
+marshaller with `JSON.registerObjectMarshaller(...)` or
`JSON.withDefaultConfiguration(...)`, declares an
+`ObjectMarshallerRegisterer` or `JsonRenderer` bean, or sets
`grails.converters.json.default.deep` or
Review Comment:
The list went with the heuristic (b520a96840): section 2 says only the
setting decides. The guide no longer names `ObjectMarshallerRegisterer` or
`InvalidRequestBodyException`.
##########
grails-converters/src/main/groovy/org/grails/web/converters/configuration/ConvertersConfigurationInitializer.java:
##########
@@ -160,6 +156,7 @@ private void initJSONConfiguration() {
ProxyHandler proxyHandler = getProxyHandler();
if (grailsConfig.getProperty(SETTING_CONVERTERS_JSON_DEFAULT_DEEP,
Boolean.class, false)) {
LOG.debug("Using DeepDomainClassMarshaller as default.");
+
ConvertersConfigurationHolder.markDefaultConfigurationCustomized(JSON.class);
Review Comment:
With the heuristic gone nothing is marked. Section 2 says the legacy
pretty-print settings do not configure Jackson and points at
`spring.jackson.serialization.indent-output`. `grails.converters.encoding`
still applies to the response, and since ae91c5e23b
`circular.reference.behaviour` applies to domain cycles.
--
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]