You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/10/14 13:51:02 UTC

(grails-core) 02/03: Copy the streamed renderers before adding the built-in ones

This is an automated email from the ASF dual-hosted git repository.

jdaugherty pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit 1c2b6b8cac6183b7bf2587dd93e2d41597200d54
Author: James Daugherty <jd...@jdresources.net>
AuthorDate: Wed Oct 14 14:48:37 2026 +0100

    Copy the streamed renderers before adding the built-in ones
    
    The streaming beans build their renderer list with toList() and then add
    the two built-in renderers to it. Groovy 5 resolves that toList() to its
    own extension method, which returns a mutable list. Groovy 6 statically
    compiles it to the JDK's Stream.toList(), whose list is unmodifiable, so
    creating publisherActionResultTransformer threw
    UnsupportedOperationException and every web application failed to start
    with streaming enabled, which is the default. The list is now copied
    before it is extended. ControllersAsyncGrailsPluginSpec failed four
    features on 9.0.x without this and passes with it.
---
 .../grails/plugins/web/async/ControllersAsyncGrailsPlugin.groovy    | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/grails-async/plugin/src/main/groovy/org/grails/plugins/web/async/ControllersAsyncGrailsPlugin.groovy b/grails-async/plugin/src/main/groovy/org/grails/plugins/web/async/ControllersAsyncGrailsPlugin.groovy
index bd28c46cfd..9fca563548 100644
--- a/grails-async/plugin/src/main/groovy/org/grails/plugins/web/async/ControllersAsyncGrailsPlugin.groovy
+++ b/grails-async/plugin/src/main/groovy/org/grails/plugins/web/async/ControllersAsyncGrailsPlugin.groovy
@@ -144,9 +144,11 @@ class ControllersAsyncGrailsPlugin extends Plugin {
                 if (jackson) {
                     builtIn << context.bean(JACKSON_RENDERER, StreamItemRenderer)
                 }
-                List<StreamItemRenderer> renderers = context.beanProvider(StreamItemRenderer).orderedStream()
+                // a copy, because the built-in renderers are added to it: Groovy 6 compiles toList() to the
+                // JDK's Stream.toList(), whose list is unmodifiable, where Groovy 5 used its own mutable one
+                List<StreamItemRenderer> renderers = new ArrayList<>(context.beanProvider(StreamItemRenderer).orderedStream()
                         .filter { StreamItemRenderer renderer -> builtIn.every { StreamItemRenderer own -> renderer !== own } }
-                        .toList()
+                        .toList())
                 renderers.addAll(builtIn)
                 new PublisherActionResultTransformer(renderers, timeout)
             }