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

Using this.method() in closures inside BuilderSupport subclasses doesn't dispatch properly

    XMLWordPrintableJSON

    Details

    • Type: Bug
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.5.9
    • Fix Version/s: 2.5.10, 4.0.0-alpha-1, 3.0.1
    • Component/s: None
    • Labels:
      None
    • Environment:
      Groovy Version: 2.5.9 JVM: 1.8.0_232 Vendor: Azul Systems, Inc. OS: Mac OS X

      Description

      Example failing script:

      #!/usr/bin/env groovy
      
      class TestClass extends BuilderSupport {
          String value = "abc"
          void thing() {
              def b = { -> this.setProperty("value", "def") }
              b()
          }
          
          Object createNode(Object a, Object b) {}
          Object createNode(Object a) {}
          Object createNode(Object a, Map b) {}
          Object createNode(Object a, Map b, Object c) {}
          void setParent(Object a, Object b) {}
      }
      
      def x = new TestClass()
      println x.value
      x.thing()
      println x.value
      

      Expected output:

      abc
      def
      

      Actual output:

      abc
      Caught: groovy.lang.MissingMethodException: No signature of method: TestClass.setProperty() is applicable for argument types: (String, String) values: [value, def]
      Possible solutions: setProperty(java.lang.String, java.lang.Object), getProperty(java.lang.String), hasProperty(java.lang.String), getProperties()
      groovy.lang.MissingMethodException: No signature of method: TestClass.setProperty() is applicable for argument types: (String, String) values: [value, def]
      Possible solutions: setProperty(java.lang.String, java.lang.Object), getProperty(java.lang.String), hasProperty(java.lang.String), getProperties()
              at TestClass$_thing_closure1.doCall(test.groovy:6)
              at TestClass.thing(test.groovy:7)
              at TestClass$thing.call(Unknown Source)
              at test.run(test.groovy:19)
      

      Explanation of what I think is going on:

      This commit changed what used to be a dispatch to the owner's metaclass into a dispatch using sender == closure class. For some reason, the metaclass looks up (closure class, "setProperty") in its MetaMethodIndex, which naturally doesn't find anything.

      The second attempt using ((GroovyObject)receiver).invokeMethod() doesn't work because BuilderSupport overrides invokeMethod and doesn't delegate back to dynamic lookup. Thus, code fails at runtime.

      Example workaround:

      class TestClass extends BuilderSupport {
          String value = "abc"
          TestClass that = this
          void thing() {
              def b = { -> that.setProperty("value", "def") }
              b()
          }
          
          Object createNode(Object a, Object b) {}
          Object createNode(Object a) {}
          Object createNode(Object a, Map b) {}
          Object createNode(Object a, Map b, Object c) {}
          void setParent(Object a, Object b) {}
      }
      
      def x = new TestClass()
      println x.value
      x.thing()
      println x.value
      

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                emilles Eric Milles
                Reporter:
                henryptung Henry Tung
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 0.5h
                  0.5h