You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Christopher Smith (JIRA)" <ji...@apache.org> on 2015/08/28 09:32:45 UTC

[jira] [Commented] (GROOVY-7559) dynamic code can write to a read-only property

    [ https://issues.apache.org/jira/browse/GROOVY-7559?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=14718151#comment-14718151 ] 

Christopher Smith commented on GROOVY-7559:
-------------------------------------------

If this is by design, *the design is wrong* in this case and should be revisited. Groovy specifically provides a direct field operator {{.@}} which can be used if direct field access is desired, and by default the dot operator uses property accessors (usually automatically generated for "boring" fields). However, from *outside the class*, the dot operator should not have the behavior of using a property accessor if available but then still directly manipulating *private* fields if the accessor is not available.

This essentially means that it's impossible to declare a controlled-access field, manipulable only through a method that enforces invariants. *Explicitly* fiddling with a field using {{.@}} is an understandable and useful hack, but the behavior of the default dot operator, especially for assignment, should not depend on such implementation details as whether a field is declared on {{Sub}} or {{Super}} and should predictably use accessors or fail when used outside the class.

> dynamic code can write to a read-only property
> ----------------------------------------------
>
>                 Key: GROOVY-7559
>                 URL: https://issues.apache.org/jira/browse/GROOVY-7559
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 2.4.4
>            Reporter: Christopher Smith
>            Assignee: Jochen Theodorou
>
> I have an {{Invoice}} class for which line items and charges can only be added through methods that enforce invariants:
> {code}
> class Invoice {
>     void calculateBalance() {...}
>     private List<LineItem> lineItems = []
>     final List<LineItem> getLineItems() {
>         lineItems.asImmutable()
>     }
>     void addLineItem(LineItem item) {
>         lineItems << item
>         calculateBalance()
>     }
>     private List<BillingTransaction> charges = []
>     @Override
>     final List<BillingTransaction> getCharges() {
>         charges.asImmutable()
>     }
>     @Override
>     void applyCharge(BillingTransaction charge) {
>         charges << charge
>         calculateBalance()
>     }
> }
> {code}
> In my Spock test, I can successfully execute {{invoice.charges = []}}, even though there's no setter for the property. Strangely, I am migrating these fields from an abstract base class (pulling out into their own class), and the read-only is enforced correctly in the unit test in that case (I literally copied and pasted, and the test started failing).
> {{javap}} indicates that no setter method is being generated. 



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)