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

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

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Closed
    • Major
    • Resolution: Fixed
    • 2.5.9
    • 2.5.10, 4.0.0-alpha-1, 3.0.1
    • None
    • None
    • 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

              emilles Eric Milles
              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