You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Paul King (Jira)" <ji...@apache.org> on 2020/02/21 03:51:01 UTC

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

     [ https://issues.apache.org/jira/browse/GROOVY-9387?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Paul King closed GROOVY-9387.
-----------------------------

> 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
>            Assignee: Eric Milles
>            Priority: Major
>             Fix For: 2.5.10, 4.0.0-alpha-1, 3.0.1
>
>          Time Spent: 0.5h
>  Remaining Estimate: 0h
>
> Example failing script:
> {code:groovy}
> #!/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
> {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.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)