Uploaded image for project: 'Groovy'
  1. Groovy
  2. GROOVY-7054

Read Only Property not resolved correctly at runtime (w/CompileDynamic)

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.3.4
    • 2.3.7, 2.4.0-beta-4
    • Compiler
    • 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
      {
      }
      

      Attachments

        Activity

          People

            blackdrag Jochen Theodorou
            ilbmiller Brad Miller
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: