[
https://issues.apache.org/jira/browse/GROOVY-12730?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King resolved GROOVY-12730.
--------------------------------
Fix Version/s: 7.0.0-alpha-1
6.0.1
Assignee: Paul King
Resolution: Fixed
> @IndexedProperty on a record component (or a @RecordType / @RecordBase class
> property) generates an indexed setter setX(int, V), even though records
> expose no setters. @Immutable classes correctly receive only the indexed
> getter
> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12730
> URL: https://issues.apache.org/jira/browse/GROOVY-12730
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 6.0.0
> Reporter: Paul King
> Assignee: Paul King
> Priority: Major
> Fix For: 7.0.0-alpha-1, 6.0.1
>
>
> h2. Reproducer
> {code:groovy}
> import groovy.transform.*
> @RecordType
> class RecordBox {
> @IndexedProperty List<String> items
> }
> @Immutable
> class ImmutableBox {
> @IndexedProperty List<String> items
> }
> def setters = { Class c -> c.declaredMethods.findAll { it.name == 'setItems'
> }*.parameterTypes*.simpleName }
> assert setters(ImmutableBox) == []
> assert setters(RecordBox) == [] // fails: [[int, String]]
> def r = new RecordBox(['a', 'b'])
> r.setItems(0, 'z') // compiles and runs
> assert r.items == ['a', 'b'] // fails: [z, b]
> {code}
> The behaviour is the same with and without joint compilation.
> h2. Cause
> {{IndexedPropertyASTTransformation}} omits the indexed setter when the field
> carries {{ImmutableASTTransformation.IMMUTABLE_BREADCRUMB}}. That marker is
> set by {{ImmutableASTTransformation.adjustPropertyForImmutability}}, but
> {{RecordTypeASTTransformation.adjustPropertyForShallowImmutability}} makes
> record fields final without setting it, so the indexed setter is still
> generated.
> h2. Notes
> * Records are only shallowly immutable: the list returned by the component
> accessor is the original (mutable) list, so the contents can already be
> changed via {{r.items()[0] = 'z'}}. The problem is therefore one of API
> consistency rather than a broken guarantee: a record has no setters, so it
> should not gain an indexed one.
> * Plain classes with a {{final}} {{@IndexedProperty}} property keep their
> indexed setter. A final reference to a mutable list is a legitimate pattern
> and is out of scope here.
> * The joint-compilation stubber ({{IndexedPropertyASTStubber}}) omits the
> setter for {{@RecordType}} / {{@RecordBase}} classes as of PR #3262
> (GROOVY-12726). This change makes the compiled class agree with the stub.
> h2. Proposed fix
> Mark record properties as read-only for {{@IndexedProperty}}, either by
> setting {{IMMUTABLE_BREADCRUMB}} in
> {{RecordTypeASTTransformation.adjustPropertyForShallowImmutability}} or by
> having {{IndexedPropertyASTTransformation}} recognise record classes
> directly. Only the indexed getter is then generated, matching {{@Immutable}}.
> This removes a public method from affected classes, so it should be noted in
> COMPATIBILITY.md and is not proposed for backporting.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)