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/05/24 01:11:00 UTC
[jira] [Updated] (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 updated GROOVY-12037:
-------------------------------
Description:
*Title:* GDK: add toMutableList/toImmutableList/toImmutableSet variants and deprecate toList(Stream) shim
*Type:* Improvement
*Component:* GDK
*Affects versions:* 6.0.0-SNAPSHOT
*Related:* GROOVY-A (cache Collectors in GDK stream and parallel extensions)
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 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 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.
was:
Add toMutableList(Stream), toImmutableList(...) and toImmutableSet(...) GDK extensions across Stream/BaseStream/Iterable/Iterator/array receivers (26 new methods total).
Deprecate the now-redundant StreamGroovyMethods.toList(Stream) shim (shadowed by native Stream.toList() since JDK 16; users should call toMutableList(Stream) when they need a mutable list).
> 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
>
> *Title:* GDK: add toMutableList/toImmutableList/toImmutableSet variants and deprecate toList(Stream) shim
> *Type:* Improvement
> *Component:* GDK
> *Affects versions:* 6.0.0-SNAPSHOT
> *Related:* GROOVY-A (cache Collectors in GDK stream and parallel extensions)
> 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 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 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)