Details
-
Type:
Bug
-
Status:
Closed
-
Priority:
Major
-
Resolution: Fixed
-
Affects Version/s: 1.8.2
-
Fix Version/s: 2.1.0-rc-1, 1.8.9, 2.0.7
-
Component/s: None
-
Labels:None
-
Number of attachments :
Description
myscript.groovy
ExpandoMetaClass.enableGlobally() Object[] myObjectArray = ['a', 'b'] as Object[] closure = { println 'closure running...' } closure(myObjectArray)
code $ groovy -version Groovy Version: 1.8.2 JVM: 1.6.0_26 code $ groovy myscript.groovy Caught: groovy.lang.MissingMethodException: No signature of method: myscript$_run_closure1.doCall() is applicable for argument types: (java.lang.String, java.lang.String) values: [a, b] Possible solutions: doCall(), doCall(java.lang.Object), call(), call([Ljava.lang.Object;), call(java.lang.Object), findAll() groovy.lang.MissingMethodException: No signature of method: myscript$_run_closure1.doCall() is applicable for argument types: (java.lang.String, java.lang.String) values: [a, b] Possible solutions: doCall(), doCall(java.lang.Object), call(), call([Ljava.lang.Object;), call(java.lang.Object), findAll() at myscript.run(myscript.groovy:9)
I have tested with versions all the way back to 1.7.0 and the exception is thrown for all the versions I tested.
If I remove the ExpandoMetaClass.enableGlobally(), the exception goes away.
I think this is related to http://jira.grails.org/browse/GRAILS-8002, though I am not sure why that problem just showed up in Grails 2.0-M2. I have not been able to reproduce it with Grails 1.3.7.
Looked a bit into it and obviously the problem is related to how ClosureMetaClass(CMC) and ExpandoMetaClass choose the method to invoke.
1) The ClosureMetaClass chooses the method to invoke via StandardClosureChooser as it finds the following two methods burnt into the class and restricts its method selection to these two going just by the number of arguments (and selects "doCall(Object)" when "closure(myObjectArray)" call is made:
2) On the other hand, the EMC makes its choice from among the following methods and chooses Closure.call(Object... args) as a more exact match:
I think the difference in behavior is arising because groovy.lang.Closure has an extra "call(Object...)" and its counterpart "doCall(Object...)" is missing in closure's bytecode. Shouln't these two sets of methods be in sync always? Once they are, we should have consistent behavior one way or another, whether CMC is used, or EMC.