Why do I need to use System.out.println instead of println when I use GroovyInterceptable?
For example if I am coding in a Groovy file I can just print to the console by typing:
println "Printing to Console"
But if I want to print here:
class Test implements GroovyInterceptable {
def sum(Integer x, Integer y) { x + y }
def invokeMethod(String name, args) {
System.out.println "Invoke method $name with args: $args"
}
}
def test = new Test()
test?.sum(2,3)
I have to use System.out.println in that method, or else I get a StackOverflowError. Why?
UPDATE:
Thanks to #Dan Getz for the answer below I know why it happens with the GroovyInterceptable class now. Does anyone know if there are other class implementations in Groovy where this issue could arise?
This is because your class Test implements the GroovyInterceptable interface, which according to the docs, is
used to notify that all methods should be intercepted through the invokeMethod mechanism of GroovyObject.
This isn't just methods that have been defined on your class. Try:
test?.total(2,3)
You'll see that it returns
Invoke method total with args: [2, 3]
The call to println inside invokeMethod is thus understood as a call to this.println, just like a call to sum would be. But this.println just calls invokeMethod again, because you implemented GroovyInterceptable, and so on.
This wouldn't happen if you didn't implement GroovyInterceptable. For example, running the following code
class Test {
def sum(Integer x, Integer y) {
println "Let's sum!"
x + y
}
}
def test = new Test()
test?.sum(2,3)
Will output
Let's sum!
Related
I am wondering what is the groovy way to accomplish something similar to Python's context manager, with it's init, enter and exit methods. Here is the basic example in Python:
class ContextManager():
def __init__(self):
print('init method called')
def __enter__(self):
print('enter method called')
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
print('exit method called')
with ContextManager() as manager:
print('with statement block')
Output:
init method called
enter method called
with statement block
exit method called
If you need your own entry points, you can write your own base class to steer this behaviour.
class ContextManager {
ContextManager() { println "init" }
void enter() { println "enter" }
void exit(Throwable t=null) { println "exit ${t?:""}" }
String getInner() { "inner" }
final run(Closure f) {
try {
enter()
f(this)
exit()
}
catch (Throwable t) {
exit(t)
}
}
}
def outer = "outer"
new ContextManager().run { manager ->
println outer
println manager.inner
println "body"
}
Output:
init
enter
outer
inner
body
exit
Groovy can accomplish something similar to this for the enter and exit using metaprogramming. Groovy has both runtime and compile-time metaprogramming. With runtime metaprogramming, you could do something similar by using invokeMethod in a class.
InvokeMethod Docs
Example
Compile-time metaprogramming is a bit more difficult because you are dealing at the compiler level:
Documentation
Simple Example
I made a Grails plugin, which would be a much more complicated example, that allows me to do something similar but invoking closures around methods:
Source
Test app
Hope some of this helps...
I tried some (runtime) metaprogramming with Groovy. I went ahead and implemented the getProperty method of GroovyInterceptable. But now I found out that this only works when getting a property on the object from the outside. When getting an property from inside a method in that class my getProperty method does not called (see the code example below).
Now, is this expected and has it always been like this? A collegue told me this used to be different in the past (from what he remembers). Is there another way where both property reads from inside and outside would call my getProperty method?
class SomeGroovyClass implements GroovyInterceptable {
def foo
SomeGroovyClass() {
foo = "ctor"
}
def getProperty(String name) {
if (name == "foo") {
return "blub"
} else {
return "foo"
}
}
def test2() {
System.out.println "foo from inside via method call: " + this.foo
}
}
def someGroovyClass = new SomeGroovyClass()
System.out.println "foo from outside: " + someGroovyClass.foo
someGroovyClass.test2()
Output is
foo from outside: blub
foo from inside via method call: ctor
One way to force the use of the getProperty method is to force the type used to access this. Changing your test2 method to:
def test2() {
println "foo from inside via method call: " + ((GroovyInterceptable) this).foo
}
results in:
~> groovy solution.groovy
foo from outside: blub
foo from inside via method call: blub
alternatives to forcing the type:
def test2() {
def me = this as GroovyInterceptable
println "foo from inside via method call: " + me.foo
}
and
def test2() {
GroovyInterceptable me = this
println "foo from inside via method call: " + me.foo
}
I can grok where the groovy compiler is coming from...there really is no way for it to know which handling of the foo property you are looking for unless you are explicit about it.
I believe the main purpose of the getProperty mechanism is to cover access of non-existent properties. This makes defaulting to the existing property when one is available a reasonable choice in my opinion and they still leave the door open as you can always force things using typed access like in the above.
A class named InterceptorTest implementing GroovyInterceptable,which could be an interceptor,has its invokeMethod overrided as follows:
class InterceptorTest implements GroovyInterceptable{
def invokeMethod(String name,args){
println "intercepting call! " //println a short message
}
}
I thought class InterceptorTest to be an interceptor would delegate all method calls to invokeMethod,so the following should work:
def interceptor=new InterceptorTest()
println interceptor.work()
Unfortunately, I got a StackOverflowError,seemingly at the body of invokeMethod,but I had no clue why it happened.
As a counterpart, I altered the function body,not println but just return message:
class InterceptorTest implements GroovyInterceptable{
def invokeMethod(String name,args){
"intercepting call! " //return a short message
}
}
then it worked fine:
def interceptor=new InterceptorTest()
println interceptor.work() //get "intercepting call!"
But WHY?
According to the documentation, "println" is actually a method in the class, injected by Groovy. Therefore, you achieve infinite recursion by trying to call it within the invokeMethod function.
We cannot use default groovy methods like println because these methods are injected into all Groovy objects so they will be intercepted too.
I need to pass a list of methods to execute inside the class with "closure way", see the code bellow
class A{
def m1(){
println "Method1"
}
def m2(){
println "Method1"
}
def commands = { closure->
println "before"
closure.call()
println "after"
}
}
A a = new A()
a.commands{
println "before execute method m1"
m1() //A need to execute m1 method of the class A
println "after execute method m1"
}
When I comment the m1() the output is
before
before execute method m1
after execute method m1
after
otherwise throw the exception MissingMethodException: No signature of method for method m1()
So, it does not recognize the m1() method as method of class A
Depending on what you are really trying to accomplish, you may want something like this...
class A{
def m1(){
println "Method1"
}
def m2(){
println "Method1"
}
def commands(closure) {
def c = closure.clone()
c.delegate = this
println "before"
c()
println "after"
}
}
The delegate gets an opportunity to respond to method calls that are made inside of the closure. Setting the delegate to this will cause the calls to m1() to be dispatched to the instance of A. You may also be interested in setting the resolveStrategy property of the closure. Valid values for resolveStrategy are Closure.DELEGATE_FIRST, Closure.OWNER_FIRST, Closure.DELEGATE_ONLY, Closure.OWNER_ONLY. The owner is the thing that created the closure and cannot be changed. The delegate can be assigned any object. When the closure makes method calls the methods may be handled by the owner or the delegate and the resolveStrategy comes into play in deciding which to use. The names DELEGATE_ONLY, OWNER_ONLY, DELEGATE_FIRST and OWNER_FIRST I think are self explanatory. If you need any more info, let me know.
I hope that helps.
I'm trying to intercept all calls to properties on a Groovy class. Since this did not work as expected, I created the following example:
class TestClass {
def getProperty(String key) {
println "getting property: " + key
}
def invokeMethod(String method, args) {
println "invoking method: " + method
}
def getFoo() {
return 1
}
}
tc.foo // 1
tc.getFoo() // 2
1) does the right thing, that is getProperty is called. However, 2) works (i.e. 1 is returned) but neither getProperty nor invokeMethod is called.
Is there a way to intercept the getfoo() call as well?
Stefan
I wrote an article a couple of months ago. You can read it here.
Try this code :
TestClass.metaClass.invokeMethod = {
def metaMethod = delegate.metaClass.getMetaMethod(method,args)
println "executing $method with args $args on $delegate"
return metaMethod.invoke(delegate,args)
}
I had to modify the code in a previous answer a bit to get what I think you want:
TestClass.metaClass.invokeMethod = {method, args ->
def metaMethod = TestClass.metaClass.getMetaMethod(method,args)
println "executing $method with args $args on $delegate"
metaMethod.invoke(delegate,args) // could result in NPE
}
Then executing
tc.foo
tc.getFoo()
Results in:
getting property: foo // println output
null // getProperty return is null
executing getFoo with args [] on TestClass#655538e5 // invokeMethod output
1 // metaMethod invocation
The problem is that there are two different kinds of paths how a request is handled is used here. For asking properties the getProperty method is called before we go into the meta class - if you overwrite getProperty you have to do the meta class call yourself actually. In case of invokeMethod it is normally asked after the meta class has been asked. Since the meta class will respond to your asking for getFoo(), invokeMethod will not be asked at all. If you let the class implement GroovyInterceptable then invokeMethod is asked first, the same way as getProperty. That also explains why the ways using the meta class instead do work.