groovy-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject new MOP under Java9 module system findings
Date Sun, 01 Apr 2018 16:33:49 GMT
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

Mime
View raw message