Hi Jochen,
I just thought about some post by another project I read some time back
(alas I can no longer remember which project exactly) which used Groovy
as its scripting language, but switched to a lesser, more restrictive
scripting option, because they needed to make the scripting more secure,
which, according to the post, could not be done using Groovy "because of
all the reflection Groovy uses". So I was wondering if changes at a
fundamental level in Groovy seem unavoidable, if it would make sense to
also keep the security aspect in mind ?
Of course you cannot be everything to everyone, even if Groovy comes
close, but if e.g. reflection usage inside a Groovy script could be
prohibited (afair that was one of the problems the post cited) within
the new, Java 9 module approach, that could conceivably make sense...
Very vague, I know, but maybe just as a general "Denkanstoß" / food for
thought,
Cheers,
mg
On 01.04.2018 18:33, Jochen Theodorou wrote:
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