Reputation: 54541
In groovy it's pretty easy to create a method closure, for example:
groovy:000> p = 1.&plus
===> org.codehaus.groovy.runtime.MethodClosure@a7981d5
groovy:000> p(3)
===> 4
However, for some reason it fails when trying to use an instance of Class
:
groovy:000> List.isInstance([])
===> true
groovy:000> t = List.&isInstance
===> org.codehaus.groovy.runtime.MethodClosure@31ca1a68
groovy:000> t([])
ERROR groovy.lang.MissingMethodException:
No signature of method: java.util.List.isInstance() is applicable for argument types: (java.util.ArrayList) values: [[]]
at groovysh_evaluate.run (groovysh_evaluate:2)
...
groovy:000> t = List.class.&isInstance
===> org.codehaus.groovy.runtime.MethodClosure@7b34c5ff
groovy:000> t([])
ERROR groovy.lang.MissingMethodException:
No signature of method: java.util.List.isInstance() is applicable for argument types: (java.util.ArrayList) values: [[]]
at groovysh_evaluate.run (groovysh_evaluate:2)
...
It's pretty easy to work around this, but I'd like to understand why this happens. Is there something in the MOP that stops this from working, etc?
Upvotes: 4
Views: 1230
Reputation: 50245
When you use a method pointer on instance of Class
then it has to explicitly use the doCall()
method provided by MethodClosure
instead of using the default call()
of Closure
.
doCall
method from MethodClosure
overrides Closure's doCall
and intercepts the method call by using invokeMethod
instead of calling call()
from Closure
.
The MethodClosure
will also work if you explicitly use the InvokerHelper
which is synonymous to doCall
in MethodClosure
or simply metaClass
List.
import org.codehaus.groovy.runtime.InvokerHelper
t = List.&isInstance
assert t.owner.simpleName == 'List'
assert t.doCall([]) == true
assert InvokerHelper.getMetaClass(t.owner).
invokeStaticMethod(t.owner, 'isInstance', []) == true
assert List.metaClass.invokeStaticMethod(t.owner, 'isInstance', []) == true
invokeStaticMethod of MOP is used if the object is an instance of Class
.
On the other hand, &plus
works appropriately because method pointer is created on a POJO.
Upvotes: 3