codeconsole commented on PR #16237:
URL: https://github.com/apache/grails-core/pull/16237#issuecomment-5459403452

   ## Deprecation migration examples
   
   This comment maps every API deprecated by this PR to its modern replacement. 
Overloads are grouped where their migration is identical.
   
   > The XML migrations intentionally change the response representation to 
JSON. The deprecated XML implementations remain available in `grails-xml` for 
clients that cannot migrate immediately.
   
   ### 1. `JSON.registerObjectMarshaller(...)` (all four overloads)
   
   This covers `(Class, Closure)`, `(Class, int, Closure)`, 
`(ObjectMarshaller)`, and `(ObjectMarshaller, int)`.
   
   Before:
   
   ```groovy
   JSON.registerObjectMarshaller(Book, 100) { Book book ->
       [id: book.id, title: book.title]
   }
   ```
   
   After, for an application-wide Jackson representation:
   
   ```groovy
   import 
org.springframework.boot.jackson.autoconfigure.JsonMapperBuilderCustomizer
   import org.springframework.context.annotation.Bean
   import tools.jackson.databind.module.SimpleModule
   
   @Bean
   JsonMapperBuilderCustomizer bookJsonCustomizer() {
       { builder ->
           builder.addModule(new SimpleModule()
                   .addSerializer(Book, new BookValueSerializer()))
       } as JsonMapperBuilderCustomizer
   }
   ```
   
   `BookValueSerializer` is a Jackson 3 `ValueSerializer<Book>`. Jackson module 
registration replaces legacy marshaller priority; serializer/module ordering 
should be made explicit when serializers overlap.
   
   ### 2. `JSON.withDefaultConfiguration(...)`
   
   Before:
   
   ```groovy
   JSON.withDefaultConfiguration {
       it.registerObjectMarshaller(Book) { Book book ->
           [id: book.id, title: book.title]
       }
   }
   ```
   
   After:
   
   ```groovy
   @Bean
   JsonMapperBuilderCustomizer bookJsonCustomizer() {
       { builder ->
           builder.addModule(new SimpleModule()
                   .addSerializer(Book, new BookValueSerializer()))
       } as JsonMapperBuilderCustomizer
   }
   ```
   
   This customizes Spring Boot's managed `JsonMapper`, so the representation is 
shared by `respond`, Spring MVC message conversion, and other Jackson 
integrations.
   
   ### 3. `JSON.createNamedConfig(...)`
   
   Before:
   
   ```groovy
   JSON.createNamedConfig('deep') {
       it.registerObjectMarshaller(Type, deepObjectMarshaller)
       it.registerObjectMarshaller(Category, deepObjectMarshaller)
   }
   ```
   
   After:
   
   ```groovy
   import grails.converters.json.NamedJsonConfigurationRegistry
   
   class BootStrap {
       NamedJsonConfigurationRegistry namedJsonConfigurationRegistry
   
       def init = { servletContext ->
           namedJsonConfigurationRegistry.register('deep') {
               it.serializer(Type, new TypeValueSerializer())
               it.serializer(Category, new CategoryValueSerializer())
           }
       }
   }
   ```
   
   The named configuration derives an isolated mapper from Boot's configured 
`JsonMapper`; it does not mutate global or thread-local converter state.
   
   ### 4. `JSON.use(String, Closure)`
   
   Before:
   
   ```groovy
   String json = JSON.use('deep') {
       new JSON(book).toString()
   }
   ```
   
   After, for direct serialization:
   
   ```groovy
   String json = namedJsonConfigurationRegistry.writeValueAsString('deep', book)
   ```
   
   Or stream directly:
   
   ```groovy
   namedJsonConfigurationRegistry.writeValue('deep', writer, book)
   ```
   
   For controller responses, the same configuration works with both APIs:
   
   ```groovy
   render book, jsonConfiguration: 'deep'
   respond book, jsonConfiguration: 'deep'
   ```
   
   ### 5. `JSON.use(String)`
   
   Before:
   
   ```groovy
   JSON.use('deep')
   try {
       String json = new JSON(book).toString()
   } finally {
       JSON.use('default')
   }
   ```
   
   After:
   
   ```groovy
   String json = namedJsonConfigurationRegistry.writeValueAsString('deep', book)
   ```
   
   Configuration is selected explicitly per operation, eliminating mutable 
thread-local state.
   
   ### 6. `JSON.getNamedConfig(String)`
   
   Before:
   
   ```groovy
   def configuration = JSON.getNamedConfig('deep')
   ```
   
   After:
   
   ```groovy
   ObjectWriter writer = namedJsonConfigurationRegistry.writer('deep')
   String json = writer.writeValueAsString(book)
   ```
   
   Registration remains encapsulated in 
`NamedJsonConfigurationRegistry.register(...)`; consumers receive the 
configured, immutable-style Jackson writer used for serialization.
   
   ### 7. `HalXmlRenderer`
   
   Before:
   
   ```groovy
   import grails.rest.render.hal.HalXmlRenderer
   
   beans = {
       halBookRenderer(HalXmlRenderer, Book)
   }
   ```
   
   After, using Grails HAL JSON:
   
   ```groovy
   import grails.rest.render.hal.HalJsonRenderer
   
   beans = {
       halBookRenderer(HalJsonRenderer, Book)
   }
   ```
   
   Clients negotiate it with:
   
   ```http
   Accept: application/hal+json
   ```
   
   Applications that prefer Spring's hypermedia model can instead add the 
optional `grails-spring-hateoas` module.
   
   ### 8. `HalXmlCollectionRenderer`
   
   Before:
   
   ```groovy
   import grails.rest.render.hal.HalXmlCollectionRenderer
   
   beans = {
       halBooksRenderer(HalXmlCollectionRenderer, Book)
   }
   ```
   
   After:
   
   ```groovy
   import grails.rest.render.hal.HalJsonCollectionRenderer
   
   beans = {
       halBooksRenderer(HalJsonCollectionRenderer, Book)
   }
   ```
   
   Clients use `Accept: application/hal+json` rather than `application/hal+xml`.
   
   ### 9. `VndErrorXmlRenderer`
   
   Before:
   
   ```groovy
   import grails.rest.render.errors.VndErrorXmlRenderer
   
   beans = {
       vndXmlErrorRenderer(VndErrorXmlRenderer)
   }
   
   // Client: Accept: application/vnd.error+xml
   respond book.errors
   ```
   
   After, using the default RFC 9457 validation response:
   
   ```groovy
   // No Vnd.Error renderer registration is required.
   // Client: Accept: application/json or application/problem+json
   respond book.errors
   ```
   
   The response uses `application/problem+json` and status 422 for validation 
failures.
   
   ### 10. XML `ValidationErrorsMarshaller`
   
   Before:
   
   ```groovy
   import grails.converters.XML
   import org.grails.web.converters.marshaller.xml.ValidationErrorsMarshaller
   
   XML.registerObjectMarshaller(new ValidationErrorsMarshaller(), 100)
   render book.errors as XML
   ```
   
   After:
   
   ```groovy
   // Client: Accept: application/json or application/problem+json
   respond book.errors
   ```
   
   Grails renders the validation errors as RFC 9457 `application/problem+json`. 
Keep the deprecated marshaller only while an existing client still requires the 
legacy XML error schema.
   


-- 
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