[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16961409#comment-16961409 ] Eric Milles edited comment on GROOVY-7996 at 10/28/19 8:36 PM: --- This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (!isPrimitiveType(getUnwrapper(testClass)) && objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { MethodNode mopMethod; if (readMode) { mopMethod = testClass.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod == null) mopMethod = testClass.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")}); } else { mopMethod = testClass.getMethod("setProperty", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); if (mopMethod == null) mopMethod = testClass.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod != null) { pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(INFERRED_TYPE); return true; } } {code} was (Author: emilles): This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { if (isPrimitiveType(testClass)) testClass = getWrapper(testClass); MethodNode mopMethod; if (readMode) { mopMethod = testClass.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod == null) mopMethod = testClass.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")}); } else { mopMethod = testClass.getMethod("setProperty", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); if (mopMethod == null) mopMethod = testClass.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE,
[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16961409#comment-16961409 ] Eric Milles edited comment on GROOVY-7996 at 10/28/19 8:32 PM: --- This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { if (isPrimitiveType(testClass)) testClass = getWrapper(testClass); MethodNode mopMethod; if (readMode) { mopMethod = testClass.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod == null) mopMethod = testClass.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")}); } else { mopMethod = testClass.getMethod("setProperty", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); if (mopMethod == null) mopMethod = testClass.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod != null) { pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(INFERRED_TYPE); return true; } } {code} was (Author: emilles): This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { MethodNode mopMethod; if (readMode) { mopMethod = testClass.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod == null) mopMethod = testClass.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")}); } else { mopMethod = testClass.getMethod("setProperty", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); if (mopMethod == null) mopMethod = testClass.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod != null) {
[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16961409#comment-16961409 ] Eric Milles edited comment on GROOVY-7996 at 10/28/19 8:20 PM: --- This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { MethodNode mopMethod; if (readMode) { mopMethod = testClass.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod == null) mopMethod = testClass.getMethod("get", new Parameter[]{new Parameter(STRING_TYPE, "name")}); } else { mopMethod = testClass.getMethod("setProperty", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); if (mopMethod == null) mopMethod = testClass.getMethod("set", new Parameter[]{new Parameter(STRING_TYPE, "name"), new Parameter(OBJECT_TYPE, "value")}); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", new Parameter[]{new Parameter(STRING_TYPE, "name")}); if (mopMethod != null) { pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(INFERRED_TYPE); return true; } } {code} was (Author: emilles): This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { MethodNode mopMethod; if (readMode) { mopMethod = receiver.getType().getMethod("getProperty", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); if (mopMethod == null) mopMethod = testClass.getMethod("get", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); } else { mopMethod = receiver.getType().getMethod("setProperty", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"), GeneralUtils.param(OBJECT_TYPE, "value"))); if (mopMethod == null) mopMethod = testClass.getMethod("set", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"), GeneralUtils.param(OBJECT_TYPE, "value"))); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); if (mopMethod != null) {
[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16961409#comment-16961409 ] Eric Milles edited comment on GROOVY-7996 at 10/28/19 7:47 PM: --- This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " def doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "assert new Bar().doStuff() == 'stuff'\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { MethodNode mopMethod; if (readMode) { mopMethod = receiver.getType().getMethod("getProperty", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); if (mopMethod == null) mopMethod = testClass.getMethod("get", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); } else { mopMethod = receiver.getType().getMethod("setProperty", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"), GeneralUtils.param(OBJECT_TYPE, "value"))); if (mopMethod == null) mopMethod = testClass.getMethod("set", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"), GeneralUtils.param(OBJECT_TYPE, "value"))); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); if (mopMethod != null) { pexp.putNodeMetaData(DYNAMIC_RESOLUTION, Boolean.TRUE); pexp.removeNodeMetaData(DECLARATION_INFERRED_TYPE); pexp.removeNodeMetaData(INFERRED_TYPE); return true; } } {code} was (Author: emilles): This is a bit of an experiment. If the initial issue is re-written this way (cut from unit test) and if I add to {{StaticTypeCheckingVisitor#existsProperty}} checks for dynamic property resolution (see below), then the test case will indeed run through {{Foo#propertyMissing}} and there will be no {{ClassCastException}}. {code:java} "Foo.groovy", "class Foo {\n" + " def build(@DelegatesTo(value=Foo, strategy=Closure.DELEGATE_FIRST) Closure block) {\n" + "return this.with(block)\n" + " }\n" + " def propertyMissing(String name) {\n" + "return 'stuff'\n" + " }\n" + "}\n", "Bar.groovy", "@groovy.transform.CompileStatic\n" + "class Bar {\n" + " protected List bars = []\n" + " String doStuff() {\n" + "new Foo().build {\n" + " return bars.toString()\n" + "}\n" + " }\n" + "}\n", "Main.groovy", "print new Bar().doStuff()\n", {code} StaticTypeCheckingVisitor: {code:java} // TODO: What if receiver implements get(String)/set(String,Object), getProperty(String)/setProperty(String,Object) or propertyMissing(String)? if (objectExpression instanceof VariableExpression && typeCheckingContext.getEnclosingClosure() != null) { MethodNode mopMethod; if (readMode) { mopMethod = receiver.getType().getMethod("getProperty", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); if (mopMethod == null) mopMethod = testClass.getMethod("get", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"))); } else { mopMethod = receiver.getType().getMethod("setProperty", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"), GeneralUtils.param(OBJECT_TYPE, "value"))); if (mopMethod == null) mopMethod = testClass.getMethod("set", GeneralUtils.params(GeneralUtils.param(STRING_TYPE, "name"), GeneralUtils.param(OBJECT_TYPE, "value"))); } if (mopMethod == null) mopMethod = testClass.getMethod("propertyMissing",
[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16960631#comment-16960631 ] Eric Milles edited comment on GROOVY-7996 at 10/27/19 3:51 PM: --- Rolling back initial changes for this issue. There were a number of other issues created by this and I think the case of a delegate having the same property name as an owner field is a bit less likely of a use case than the others. Also, there are at east 2 workarounds available for this issue: 1) specify the closure as OWNER_FIRST and 2) use "owner" or "thisObject" or "this" qualifier on field access. A number of test cases have been added so if a fix is approached for this again, there will be less chance of breaking other closure variable expression access scenarios. was (Author: emilles): Rolling back initial changes for this issue. There were a number of other issues created by this and I think the case of a delegate having the same property name as an owner field is a bit less likely of a use case than the others. A number of test cases have been added so if a fix is approached for this again, there will be less chance of breaking other closure variable expression access scenarios. > Using with method with a closure that references a protected property > produces ClassCastException > - > > Key: GROOVY-7996 > URL: https://issues.apache.org/jira/browse/GROOVY-7996 > Project: Groovy > Issue Type: Bug >Affects Versions: 2.4.7 >Reporter: Graeme Rocher >Priority: Major > Fix For: 2.5.6, 3.0.0-beta-1 > > Time Spent: 0.5h > Remaining Estimate: 0h > > The following example: > {code} > class Foo { > Object propertyMissing(String name) { > return "stuff" > } > > void build(Closure callable) { > this.with(callable) > } > } > @groovy.transform.CompileStatic > class Bar { > protected List bar = [] > > boolean doStuff() { > Foo foo = new Foo() > foo.build { >return bar.isEmpty() > } > } > } > new Bar().doStuff() > {code} > Produces > {code} > java.lang.ClassCastException: java.lang.String cannot be cast to > java.util.List > at Bar$_doStuff_closure1.doCall(ConsoleScript3:19) > at Bar$_doStuff_closure1.call(ConsoleScript3) > at > org.codehaus.groovy.runtime.DefaultGroovyMethods.with(DefaultGroovyMethods.java:242) > at Bar.doStuff(ConsoleScript3:18) > at Ba > {code} > The equivalent code without CompileStatic prints: > {code} > Result: false > {code} > The behaviour of both should be he same IMO -- This message was sent by Atlassian Jira (v8.3.4#803005)
[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16821458#comment-16821458 ] Eric Milles edited comment on GROOVY-7996 at 4/18/19 8:04 PM: -- If written this way, no error occurs on Groovy 2.4: {code} class Foo { def propertyMissing(String name) { return 'stuff' } def build(@DelegatesTo(value=Foo, strategy=Closure.OWNER_FIRST) Closure block) { block.delegate = this return block.call() } } @groovy.transform.CompileStatic class Bar { protected List bars = [] boolean doStuff() { new Foo().build { return bars.isEmpty() } } } {code} This should return {{true}} for {{new Bar().doStuff()}} since {{build}} now returns the value returned from the closure. was (Author: emilles): If written this way, no error occurs on Groovy 2.4: {code:groovy} class Foo { def propertyMissing(String name) { return 'stuff' } def build(@DelegatesTo(value=Foo, strategy=Closure.OWNER_FIRST) Closure block) { block.delegate = this return block() } } @groovy.transform.CompileStatic class Bar { protected List bars = [] boolean doStuff() { new Foo().build { return bars.isEmpty() } } } {code} This should return {{true}} for {{new Bar().doStuff()}} since {{build}} now returns the value returned from the closure. > Using with method with a closure that references a protected property > produces ClassCastException > - > > Key: GROOVY-7996 > URL: https://issues.apache.org/jira/browse/GROOVY-7996 > Project: Groovy > Issue Type: Bug >Affects Versions: 2.4.7 >Reporter: Graeme Rocher >Assignee: Paul King >Priority: Major > Fix For: 2.5.6, 3.0.0-beta-1 > > Time Spent: 0.5h > Remaining Estimate: 0h > > The following example: > {code} > class Foo { > Object propertyMissing(String name) { > return "stuff" > } > > void build(Closure callable) { > this.with(callable) > } > } > @groovy.transform.CompileStatic > class Bar { > protected List bar = [] > > boolean doStuff() { > Foo foo = new Foo() > foo.build { >return bar.isEmpty() > } > } > } > new Bar().doStuff() > {code} > Produces > {code} > java.lang.ClassCastException: java.lang.String cannot be cast to > java.util.List > at Bar$_doStuff_closure1.doCall(ConsoleScript3:19) > at Bar$_doStuff_closure1.call(ConsoleScript3) > at > org.codehaus.groovy.runtime.DefaultGroovyMethods.with(DefaultGroovyMethods.java:242) > at Bar.doStuff(ConsoleScript3:18) > at Ba > {code} > The equivalent code without CompileStatic prints: > {code} > Result: false > {code} > The behaviour of both should be he same IMO -- This message was sent by Atlassian JIRA (v7.6.3#76005)
[jira] [Comment Edited] (GROOVY-7996) Using with method with a closure that references a protected property produces ClassCastException
[ https://issues.apache.org/jira/browse/GROOVY-7996?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel=16748379#comment-16748379 ] Paul King edited comment on GROOVY-7996 at 1/22/19 4:46 AM: Proposed PR merged. Workaround is to use `owner.bar.isEmpty()` orĀ `this.bar.isEmpty()` was (Author: paulk): Proposed PR merged. > Using with method with a closure that references a protected property > produces ClassCastException > - > > Key: GROOVY-7996 > URL: https://issues.apache.org/jira/browse/GROOVY-7996 > Project: Groovy > Issue Type: Bug >Affects Versions: 2.4.7 >Reporter: Graeme Rocher >Assignee: Paul King >Priority: Major > Fix For: 2.5.6, 3.0.0-alpha-5 > > Time Spent: 20m > Remaining Estimate: 0h > > The following example: > {code} > class Foo { > Object propertyMissing(String name) { > return "stuff" > } > > void build(Closure callable) { > this.with(callable) > } > } > @groovy.transform.CompileStatic > class Bar { > protected List bar = [] > > boolean doStuff() { > Foo foo = new Foo() > foo.build { >return bar.isEmpty() > } > } > } > new Bar().doStuff() > {code} > Produces > {code} > java.lang.ClassCastException: java.lang.String cannot be cast to > java.util.List > at Bar$_doStuff_closure1.doCall(ConsoleScript3:19) > at Bar$_doStuff_closure1.call(ConsoleScript3) > at > org.codehaus.groovy.runtime.DefaultGroovyMethods.with(DefaultGroovyMethods.java:242) > at Bar.doStuff(ConsoleScript3:18) > at Ba > {code} > The equivalent code without CompileStatic prints: > {code} > Result: false > {code} > The behaviour of both should be he same IMO -- This message was sent by Atlassian JIRA (v7.6.3#76005)