Paul King created GROOVY-12730:
----------------------------------
Summary: @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
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)