groovy
  1. groovy
  2. GROOVY-2503 MOP 2.0 design inflluencing issues
  3. GROOVY-2913

Closure and binding with static finals from extended classes leads to an exception.

    Details

    • Type: Sub-task Sub-task
    • Status: Reopened Reopened
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.5.6, 1.6-beta-1
    • Fix Version/s: None
    • Component/s: groovy-runtime
    • Labels:
      None
    • Testcase included:
      yes
    • Number of attachments :
      0

      Description

      The following code produces an error

      static final String A = 'a'
      
          void testA() {
              def closure = {
                  println A
              }
              closure()
          }
          void testC() {
              println(A)
              def closure = {
                  println AbstractClass.A
              }
              closure()
        }
      
      class ConcreteClassTest extends AbstractClassTest {
          static final String B = 'b'
      
          void testB() {
              println(B)
              def closure = {
                  println B
              }
              closure()
          }
      }
      

      If I run ConcreteClassTest, testB and testC works fine but testA throws an exception.

      The stacktrace is:

      groovy.lang.MissingPropertyException: No such property: A for class: ConcreteClass
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:49)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:59)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:169)
      	at AbstractClass.getProperty(AbstractClass.groovy)
      	at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:172)
      	at groovy.lang.Closure.getPropertyTryThese(Closure.java:200)
      	at groovy.lang.Closure.getPropertyOwnerFirst(Closure.java:216)
      	at groovy.lang.Closure.getProperty(Closure.java:186)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.getGroovyObjectProperty(ScriptBytecodeAdapter.java:532)
      	at AbstractClass$_testA_closure1.doCall(AbstractClass.groovy:28)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:226)
      	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodOnCurrentN(ScriptBytecodeAdapter.java:77)
      	at AbstractClass$_testA_closure1.doCall(AbstractClass.groovy)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:86)
      	at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:226)
      	at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:248)
      	at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:754)
      	at org.codehaus.groovy.runtime.InvokerHelper.invokePogoMethod(InvokerHelper.java:779)
      	at org.codehaus.groovy.runtime.InvokerHelper.invokeMethod(InvokerHelper.java:759)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:167)
      	at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeClosure(ScriptBytecodeAdapter.java:602)
      	at AbstractClass.testA(AbstractClass.groovy:30)
      	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
      	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
      	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
      

        Issue Links

          Activity

          Hide
          Hans Dockter added a comment -
          Show
          Hans Dockter added a comment - See also the discusion in the mailing list: http://www.nabble.com/Closure-and-binding-with-static-finals-from-abstract-classes-to16512010.html
          Hide
          blackdrag blackdrag added a comment -

          Hans, your code is not all that clear... Could you please modify the code to a unit test? Because unlike that time, the code makes no sense to me today... If the above is a script, then testA and testB should fail... well, that is not even a test. If I change your code to this:

          class ConcreteClassTest extends AbstractClass {
              static final String B = 'b'
          
              void testB() {
                  println(B)
                  def closure = {
                      println B
                  }
                  closure()
              }
          }
          
          class AbstractClass extends GroovyTestCase {
           static final String A = 'a'
          
              void testA() {
                  def closure = {
                      println A
                  }
                  closure()
              }
              void testC() {
                  println(A)
                  def closure = {
                      println AbstractClass.A
                  }
                  closure()
            }
          }
          

          then I have no failing tests.So currently I can not reproduce your problem

          Show
          blackdrag blackdrag added a comment - Hans, your code is not all that clear... Could you please modify the code to a unit test? Because unlike that time, the code makes no sense to me today... If the above is a script, then testA and testB should fail... well, that is not even a test. If I change your code to this: class ConcreteClassTest extends AbstractClass { static final String B = 'b' void testB() { println(B) def closure = { println B } closure() } } class AbstractClass extends GroovyTestCase { static final String A = 'a' void testA() { def closure = { println A } closure() } void testC() { println(A) def closure = { println AbstractClass.A } closure() } } then I have no failing tests.So currently I can not reproduce your problem
          Hide
          blackdrag blackdrag added a comment -

          I am closing the issue for now, since I have nothing to reproduce the problem. If there is a failing test case we can still reopen the issue

          Show
          blackdrag blackdrag added a comment - I am closing the issue for now, since I have nothing to reproduce the problem. If there is a failing test case we can still reopen the issue
          Hide
          Hans Dockter added a comment -

          Sorry, the snippet I have pasted in my original comment was broken. Here a failing TestCase:

          import junit.framework.TestCase
          
          class AbstractClassTest extends TestCase {
             static final String A = 'a'
          
              void testA() {
                  def closure = {
                      println A
                  }
                  closure()
              }
              void testC() {
                  println(A)
                  def closure = {
                      println AbstractClassTest.A
                  }
                  closure()
            }
          }
          
          class ConcreteClassTest extends AbstractClassTest {
              static final String B = 'b'
          
              void testB() {
                  println(B)
                  def closure = {
                      println B
                  }
                  closure()
              }
          }
          

          If you execute ConcreteClassTest it fails.

          Show
          Hans Dockter added a comment - Sorry, the snippet I have pasted in my original comment was broken. Here a failing TestCase: import junit.framework.TestCase class AbstractClassTest extends TestCase { static final String A = 'a' void testA() { def closure = { println A } closure() } void testC() { println(A) def closure = { println AbstractClassTest.A } closure() } } class ConcreteClassTest extends AbstractClassTest { static final String B = 'b' void testB() { println(B) def closure = { println B } closure() } } If you execute ConcreteClassTest it fails.
          Hide
          blackdrag blackdrag added a comment -

          I am afraid a fix for this bug requires a MOP change, because the property access inside the closure looses some information on the way. MOP change means it has to wait for 2.0. Ideally we would transform the property access in a field access, but that is a change to the MOP in a certain way

          Show
          blackdrag blackdrag added a comment - I am afraid a fix for this bug requires a MOP change, because the property access inside the closure looses some information on the way. MOP change means it has to wait for 2.0. Ideally we would transform the property access in a field access, but that is a change to the MOP in a certain way
          Hide
          blackdrag blackdrag added a comment -

          This issue has common ground with GROOVY-1569. Only that this issue here handles subclasses while the other one focuses on field access. In general both are candidates for GROOVY-2503

          Show
          blackdrag blackdrag added a comment - This issue has common ground with GROOVY-1569 . Only that this issue here handles subclasses while the other one focuses on field access. In general both are candidates for GROOVY-2503

            People

            • Assignee:
              blackdrag blackdrag
              Reporter:
              Hans Dockter
            • Votes:
              0 Vote for this issue
              Watchers:
              0 Start watching this issue

              Dates

              • Created:
                Updated: