Hi all,
yesterday I was playing around with java modules and tried to implement
some pseudo mops based on what we have and I'd like to share my
impressions. Please do not wonder that I only mention method invocation,
I only played around with that.
missingMethod seems to be easy to do, also builders based on
missingMethod instead of invokeMethod will do in the form we have now. I
managed to do that with a mini meta class, that uses reflection to
inspect the class (no setAccessible).
The bad part here is that the actual invocation will have to be using
MethodHandles, which requires us to create them of course, which is not
good for performance if we have to unreflect the methods. But a new meta
class system could take care of that at the price of increasing the meta
class creation time. But I think these problems can be solved.
In my mini mop I was able to call private methods without helper methods
and also from inner classes. But when I mention private methods I do
mean methods we would have access to in Java as well. This is done by
the class doing the call providing a Lookup object, which allows me to
make calls on behalf of the caller class. Which means I can *not* call
private methods from arbitrary classes. This means you will no longer be
able to write unit tests in Groovy, able to tests private methods from
Java classes... unless we preprocess the classes and make a lookup
object available. For Groovy classes we could provide such a mechanism
by default, but frankly I would not do that, because that lookup object
means you can access all the internals of the class without restrictions
and that without any security manager.
The problem child in our current mop here is invokeMethod. methodMissing
is at the end of the mop and while it does not matter there to loose the
caller context we can keep them as is. But invokeMethod tends to be more
in between there is a potential problem. As long as invokeMethod is for
the current class, there is no trouble, but calling into a another class
from invokeMethod means to use the context of the class invokeMethod is
in and loosing the original context. Especially that logic to just call
to meta class in invokeMethod is a problem.
Example:
class LogProxy {
def orig
def invokeMethod(String name, Object args) {
println "called method $name"
orig."$name"(*args)
}
}
class Foo {
def proxy = new LogProxy(orig:this)
private method(){}
def publicMethod() {
proxy.method()
}
}
This kind of code can work in Groovy, as long as we are not working on a
subclass of Foo. To make this work with modules where LogProxy is from
another module as Foo, I think the only way is to expose the lookup
object and use that for the creation of the handle. But that means it
has to be part of the call orig."$name"(*args) and of the method
signature of invokeMethod.
In summary I think all the cases where our mop methods operate as
endpoints can be made work. But that means invokeMethod can no longer
work as entry point and actually becomes the same as methodMissing,
which begs the question if it should even exist. Similar cases can be
made for get(String) and others. For invokeMethod as entry point to
method invocation the signature would have to change to contain the
Lookup object at least, and a way to invoke a method using that lookup
object.
bye Jochen