You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (Jira)" <ji...@apache.org> on 2026/10/20 01:27:02 UTC

[jira] [Closed] (GROOVY-12037) GDK: add toMutableList/toImmutableList/toImmutableSet variants and deprecate toList(Stream) shim

     [ https://issues.apache.org/jira/browse/GROOVY-12037?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Paul King closed GROOVY-12037.
------------------------------

> GDK: add toMutableList/toImmutableList/toImmutableSet variants and deprecate toList(Stream) shim
> ------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12037
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12037
>             Project: Groovy
>          Issue Type: New Feature
>            Reporter: Paul King
>            Assignee: Paul King
>            Priority: Major
>             Fix For: 6.0.0-alpha-2
>
>
> h2. Problem
> The GDK exposes only mutable conversions ({{toList}}/{{toSet}}) from {{Stream}}, {{BaseStream}}, {{Iterator}}, {{Iterable}} and arrays. Users wanting immutable results have to chain JDK helpers ({{List.copyOf}}, {{Collectors.toUnmodifiableSet}}) — or, since JDK 16, silently get one from {{stream.toList()}}: that call now resolves to the native {{Stream#toList()}} (unmodifiable) rather than the GDK extension (mutable {{ArrayList}}), with no compiler signal. Code that mutated the result and worked pre-JDK&nbsp;16 can now throw {{UnsupportedOperationException}} after an unrelated JDK upgrade.
> h2. Changes
> * *Add {{toImmutableList}} / {{toImmutableSet}}* across every receiver that already has {{toList}}/{{toSet}}: {{BaseStream}}, {{Iterator}}, {{Iterable}}, {{T[]}}, and all 8 primitive array types. {{toImmutableSet}} also added for {{Stream}}. ({{toImmutableList(Stream)}} is omitted — native {{Stream#toList()}} already covers it.)
> * *Add explicit-mutability {{toMutableList}} / {{toMutableSet}}* for {{Stream}} and {{BaseStream}}, so user intent stays unambiguous and the GDK is defensively positioned against any future JDK release adding more native instance methods that would shadow GDK extensions the way native {{Stream#toList()}} did.
> * *Deprecate {{StreamGroovyMethods.toList(Stream)}}* — shadowed in both static and dynamic dispatch by native {{Stream#toList()}} on JDK&nbsp;16+, so the method is effectively dead code in idiomatic call sites. Migration: {{toMutableList(Stream)}} for an explicit mutable list, native {{stream.toList()}} for an immutable one. The javadoc on the deprecated method is also updated to flag the JDK-16+ semantic shift for anyone who lands on it.
> h2. Scope
> || File || New methods || Other ||
> | {{StreamGroovyMethods}} | 7 ({{toMutableList(Stream)}}, {{toMutableList(BaseStream)}}, {{toMutableSet(Stream)}}, {{toMutableSet(BaseStream)}}, {{toImmutableList(BaseStream)}}, {{toImmutableSet(Stream)}}, {{toImmutableSet(BaseStream)}}) | +1 cached {{Collector}} ({{TO_UNMODIFIABLE_SET}}) used by the new immutable Set methods; 1 deprecation; javadoc note |
> | {{DefaultGroovyMethods}} | 4 ({{toImmutableList(Iterator)}}, {{toImmutableList(Iterable)}}, {{toImmutableSet(Iterator)}}, {{toImmutableSet(Iterable)}}) | — |
> | {{ArrayGroovyMethods}} | 18 ({{toImmutableList}}/{{toImmutableSet}} × {{T[]}} + 8 primitive arrays) | — |
> 29 new methods total, 1 deprecation. Fully additive: no public-API change to existing methods beyond the {{@Deprecated}} annotation and javadoc.
> h2. Compatibility
> * No source or binary breakage for any existing caller.
> * The deprecation produces no warnings on internal Groovy code: only callers of {{StreamGroovyMethods.toList(Stream)}} are themselves {{@Deprecated}} bridge methods (in {{PluginDefaultGroovyMethods}}), and javac's {{-Xlint:deprecation}} does not flag {{@Deprecated → @Deprecated}} calls.
> * Users on JDK 16+ writing idiomatic {{stream.toList()}} are already getting the native call — no change for them.
> * The only callers who will see the deprecation warning are those explicitly invoking the GDK extension via the static-method form ({{StreamGroovyMethods.toList(stream)}}), which is exactly the audience that needs to make an informed mutable-vs-immutable choice.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)