Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Fixed
-
2.3.4
-
None
-
Windows
Description
I hit an issue where I was getting a MissingPropertyException if I used @CompileDynamic, but the exception went away with @CompileStatic. Below is a simple junit test that isolates the behavior, and the underlying issue is how a read-only private property (via getter) of a parent class is resolved at runtime by @CompileDynamic versus @CompileStatic. The CompileDynamicParentPrivateTest.testCDPrivate() test throws a runtime MissingPropertyException when a method in the parent class tries to access the the parent class's private property 'foo' (as opposed to via getFoo())
One possible explanation - it appears that the groovy 'foo' property is resolved dynamically when using @CompileDynamic, and as the property is private within the parent class the resolution on the child instance fails (however, why does getFoo() succeed then?). When @CompileStatic is used, the normal (java) lexical scoping rules apply, and the parent private property can be resolved correctly within the parent method.
1. Is this a bug, or an expected difference in behavior for @CompileStatic / @CompileDynamic?
2. And is my explanation correct as to what is happening?
3. And how can getFoo() succeed, but 'foo' fail, when using @CompileDynamic? Shouldn't they always behave the same?
Thanks,
Brad
-----------------------------------
Groovy 2.3.4
testCSPrivate succeeds, while second test (testCDPrivate) fails with following exception on second println statement:
groovy.lang.MissingPropertyException: No such property: foo for class: myBugReport.bug2.CDChild
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:50)
at org.codehaus.groovy.runtime.callsite.GetEffectivePogoPropertySite.getProperty(GetEffectivePogoPropertySite.java:84)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:231)
at myBugReport.bug2.CDParent.printWhichAccessesPrivatePropOfParent(CompileDynamicParentPrivateTest.groovy:53)
at myBugReport.bug2.CDParent$printWhichAccessesPrivatePropOfParent.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:112)
at myBugReport.bug2.CompileDynamicParentPrivateTest.testCDPrivate(CompileDynamicParentPrivateTest.groovy:22)
-----------------------------------
package myBugReport.bug2 import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import org.junit.Test class CompileDynamicParentPrivateTest { // This test SUCCEEDS as CompileStatic parent class can access private read-only property 'foo' @Test public void testCSPrivate() { CSChild csChild = new CSChild() csChild.printWhichAccessesPrivatePropOfParent() } // This test FAILS as CompileDynamic parent class can NOT access private read-only property 'foo' @Test public void testCDPrivate() { CDChild cdChild = new CDChild() cdChild.printWhichAccessesPrivatePropOfParent() } } @CompileStatic class CSParent { // Read-only property where only the getter is defined (without a backing field) private String getFoo() { return "bar" } void printWhichAccessesPrivatePropOfParent() { System.out.println("Current value of getFoo() is: " + getFoo()) // works System.out.println("Current value of foo is: " + foo) // works with CompileStatic only } } @CompileStatic class CSChild extends CSParent { } @CompileDynamic class CDParent { // Read-only property where only the getter is defined (without a backing field) private String getFoo() { return "bar" } void printWhichAccessesPrivatePropOfParent() { System.out.println("Current value of getFoo() is: " + getFoo()) // works System.out.println("Current value of foo is: " + foo) // foo breaks with CompileDynamic only } } @CompileDynamic class CDChild extends CDParent { }