You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Henry Tung (Jira)" <ji...@apache.org> on 2020/02/08 00:28:00 UTC

[jira] [Created] (GROOVY-9387) Using this.method() in closures inside BuilderSupport subclasses doesn't dispatch properly

Henry Tung created GROOVY-9387:
----------------------------------

             Summary: Using this.method() in closures inside BuilderSupport subclasses doesn't dispatch properly
                 Key: GROOVY-9387
                 URL: https://issues.apache.org/jira/browse/GROOVY-9387
             Project: Groovy
          Issue Type: Bug
    Affects Versions: 2.5.9
         Environment: Groovy Version: 2.5.9 JVM: 1.8.0_232 Vendor: Azul Systems, Inc. OS: Mac OS X
            Reporter: Henry Tung


Example failing script:
{code:groovy}
#!/usr/bin/env groovy

class TestClass extends BuilderSupport {
    String value = "abc"
    void thing() {
        def b = { -> this.test(); 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
{code}
Expected output:
{noformat}
abc
def
{noformat}
Actual output:
{noformat}
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)
{noformat}
Explanation of what I think is going on:

[This commit|https://github.com/apache/groovy/commit/34ad466ba6a87a5eb26cf4a444f817299b744edb#diff-ba71c5ea5d5201ae4da0b6a7b7e46137L66] 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:
{code:groovy}
class TestClass extends BuilderSupport {
    String value = "abc"
    TestClass that = this
    void thing() {
        def b = { -> that.test(); 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
{code}



--
This message was sent by Atlassian Jira
(v8.3.4#803005)