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

ASF GitHub Bot commented on GROOVY-12671:
-----------------------------------------

codeconsole opened a new pull request, #3192:
URL: https://github.com/apache/groovy/pull/3192

   An implicit-this property read or write in a closure with resolve strategy 
`OWNER_FIRST` and a null owner never reaches the delegate. It throws 
`NullPointerException: Cannot get property 'bar' on null object`:
   
   ```groovy
   class D { def bar = 'delegate' }
   def c = { -> bar }.dehydrate()
   c.delegate = new D()
   assert c() == 'delegate' // NPE
   ```
   
   `Closure.resolveGetProperty` and `resolveSetProperty` skipped a null 
receiver only for `DELEGATE_FIRST` with a null delegate (GROOVY-1974). Every 
other null owner or delegate went to `NullObject`. The same NPE replaced 
`MissingPropertyException` when both were null, and when an `OWNER_ONLY` owner 
or a `DELEGATE_ONLY` delegate was null. In addition, `setPropertyTryThese` 
guarded its fallback with `o1 != null` instead of `o2 != null`, so writing a 
property the first candidate lacks went on to set it on a null second 
candidate. Seen in every release back to 2.4.15.
   
   The private `getProperty`/`setProperty` helpers now throw 
`MissingPropertyException` for a null receiver, and the `*TryThese` helpers 
move straight to the second candidate when the first is null. The 
`DELEGATE_FIRST` special case is covered by the general rule and is removed. 
Property resolution now matches method dispatch as fixed by #3188 
(GROOVY-12667): a null owner or delegate is skipped, and if nothing is left, a 
missing-member exception (naming the closure class) is thrown. The indy and 
classic call-site paths both go through these methods. Code that caught the NPE 
for an `OWNER_ONLY`/`DELEGATE_ONLY` closure with a null target now sees 
`MissingPropertyException`.
   
   This touches `Closure` only; #3188 touches `ClosureMetaClass`, and the two 
merge cleanly.
   
   ## Tests
   
   `ClosureTest` gains `testOwnerFirstWithNullOwnerProperty` (read, write, 
compound assignment), `testOwnerFirstWithNullOwnerPropertyTypeChecked`, 
`testDehydratedClosureWithDelegateProperty`, 
`testMissingPropertyWithNullOwnerAndDelegate`, 
`testMissingPropertyWithNullOnlyCandidate` and 
`testMissingPropertyWithNullSecondCandidate`. All 11 cases fail without the 
change. `groovy.lang.*Closure*`, `groovy.*Closure*`, `gls.invocation.*`, 
`org.codehaus.groovy.runtime.*`, `groovy.transform.stc.*`, 
`org.codehaus.groovy.classgen.asm.sc.*` and `groovy.ThisAndSuperTest` pass. The 
Checkstyle and CodeNarc gates pass.
   




> Closure property access throws NullPointerException instead of falling 
> through to the delegate when the owner is null
> ---------------------------------------------------------------------------------------------------------------------
>
>                 Key: GROOVY-12671
>                 URL: https://issues.apache.org/jira/browse/GROOVY-12671
>             Project: Groovy
>          Issue Type: Bug
>    Affects Versions: 4.0.33, 5.0.8, 7.0.0-alpha-1, 6.0.0
>            Reporter: Scott Murphy Heiberg
>            Priority: Major
>
> {code:groovy}
> class D { def bar = 'delegate' }
> def c = { -> bar }.dehydrate()
> c.delegate = new D()
> assert c() == 'delegate'
> {code}
> *Actual:* {{java.lang.NullPointerException: Cannot get property 'bar' on null 
> object}}. A write ({{bar = 1}}) throws {{Cannot set property 'bar' on null 
> object}}, and so does {{rehydrate(d, null, null)}}.
> *Expected:* with OWNER_FIRST (the default) a null owner is skipped and the 
> delegate supplies the property, the same as for method calls (GROOVY-12667). 
> When no non-null candidate remains (both null, or a null target under 
> OWNER_ONLY or DELEGATE_ONLY), MissingPropertyException is thrown, matching 
> the MissingMethodException that method calls give.
> {{Closure.resolveGetProperty}} and {{resolveSetProperty}} skip a null 
> receiver only for DELEGATE_FIRST with a null delegate (GROOVY-1974). Every 
> other null receiver reaches {{NullObject}}. Separately, 
> {{setPropertyTryThese}} tests {{o1 != null}} where it should test {{o2 != 
> null}}, so a missing property on the owner with a null delegate also throws 
> NPE instead of MissingPropertyException.
> Verified on 2.4.15, 3.0.25, 4.0.33, 5.0.8, 6.0.0 and master.



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to