Groovy: add a method to a closure - groovy

I have the following closure
def closure = {
println ("closure code")
}
And i would like to add a method to it.
but if I try
closure.metaClass.fun = { c->
c.call();
println ("extra code");
}
I get an Exception
groovy.lang.MissingPropertyException: No such property: fun for class: org.codehaus.groovy.runtime.metaclass.ClosureMetaClass
Reading another answer, i also blindly tried to call
ExpandoMetaClass.enableGlobally()
but it's not working.
Is there a way to achive what I want?

You can do:
def closure = {
println "closure code"
}
closure.getMetaClass().fun = { ->
delegate.call()
println "extra code"
}
closure.fun()
Which prints:
closure code
extra code

Another simpler approach could be:
def closure = {
println "closure code"
}
closure.fun = { ->
closure()
println "extra code"
}
closure.fun()
The downside of this approach is that I'm referencing the closure variable directly though, instead of going through the delegate.

Related

How to get closure delegate to be used correctly when called within a Trait

I have a Groovy trait which needs to provide a config Closure as an argument to a library method call (it's HttpBuilder but it shouldn't matter).
For reproducing the issue, I created the following simple example:
trait T {
def doIt() {
return {
n = 1
}
}
}
class Delegate {
int n
}
class Tish implements T {
def go() {
def closure = doIt()
def d = new Delegate()
closure.delegate = d
closure()
assert d.n == 1
}
}
new Tish().go()
This is expected to run without errors because when the closure returned by the doIt() method in the T trait is run, its delegate is set to something that can set the n variable to 1....
However, this does not work and I get this error:
groovy.lang.MissingPropertyException: No such property: n for class: Tish
If I make T a class and let Tish extend it instead, then it works!
I tried changing the Closure's delegate strategy but that did not help.
Is this a Groovy bug or is there a way to work around this issue?
Alright, I found a workaround... Still, would be interesting to know if this is a bug, and if it is, when it will get fixed by the Groovy team!
UPDATE: this is a bug and hopefully will be fixed in a Groovy release in the near future!
All calls made within the config Closure can get the actual Delegate object by calling the getDelegate() method, then setting all properties directly on it, like this:
return {
def d = getDelegate()
d.n = 1
}
Not ideal, but got me unstuck, hope it helps others...
EDIT:
As pointed about by #bdkosher in the comments, another solution is to use setter syntax in the closure:
return {
setN 1
}
Change your code from
def d = new Delegate()
closure.delegate = d
closure()
to
def d = new Delegate()
closure.delegate = d
closure.run()
this solved a pretty similar issue, that i had with Grails 3.3.8, Groovy 2.4.15, Java 1.8.0_131. No idea why but it helped.
I was trying to chase down the error and added the following outputs
println this
println owner
println delegate
and figured out that in the first case delegate was not changed even closure.delegate = d was set before executing closure()! If closure.run() is called then delegate was set correctly!?!

Groovy : how to pass closure as parameter to execute the methods inside the class

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.

How do I intercept calls in Groovy?

I have this class structure:
interface bug
{
def method()
}
public class A implements bug{
def method()
{
println "Works"
}
}
A varaiable = new A()
bug.metaClass.invokeMethod {
name,args ->
println "Came here"
}
varaiable.method()
when I do this, I get Works. Why not Came here?
Where I'm doing the mistake?
EDIT:
Even if I do:
A.metaClass.invokeMethod {
name,args ->
println "Came here"
}
I'm getting only Works.
​
You're changing the metaClass of A with
A.metaClass.invokeMethod { name,args ->
println "Came here"
}
After you construct the variable. If you put this block before the line
A varaiable = new A()
It should work as you'd expect.
To get round this, you can use:
ExpandoMetaClass.enableGlobally()
And instances will check back with the metaClass every invocation, however as expected this can slow things down

Groovy methodMissing

I have a closure within an object Foo and inside the closure i define a method called 'myStaticMethod' that I want to resolve once the closure is called outside the object Foo. I also happen to have 'on purpose' a static method within my object Foo with the same name. When I call the closure i set the 'resolve strategy' to DELEGATE_ONLY to intercept the call to myStaticMethod that is defined within the closure.
I tried to achieve that through missingMethod but the method is never intercepted. When i make the Foo.myStaticMethod non static, the method is intercepted. I don't quite understand why this is happening though my resolve strategy is set to DELEGATE_ONLY. having the Foo.myStaticMethod static or not shouldn't matter or I am missing something
class Foo {
static myclosure = {
myStaticMethod()
}
static def myStaticMethod() {}
}
class FooTest {
def c = Foo.myclosure
c.resolveStrategy = Closure.DELEGATE_ONLY
c.call()
def missingMethod(String name, def args) {
println $name
}
}
To solve the problem, I ended up overriding the invokeMethod right before calling the closure in FooTests
Foo.metaClass.'static'.invokeMethod = { String name, args ->
println "Static Builder processing $name "
}
While trying to solve this problem, i discovered a very weird way to intercept missing static methods. Might be useful to some of you in the future.
static $static_methodMissing(String name, args) {
println "Missing static $name"
}
-Ken
Static methods unfortunately aren't intercepted by the closure property resolution. The only way that I know to intercept those is to override the static metaClass invokeMethod on the class that owns the closure, ex:
class Foo {
static myclosure = {
myStaticMethod()
}
static myStaticMethod() {
return false
}
}
Foo.metaClass.'static'.invokeMethod = { String name, args ->
println "in static invokeMethod for $name"
return true
}
def closure = Foo.myclosure
assert true == closure()

replacing toString using Groovy metaprogramming

In the following Groovy snippet, I attempt to replace both the hashCode and toString methods
String.metaClass.toString = {-> "override" }
String.metaClass.hashCode = {-> 22 }
But when I test it out, only the replacement of hashCode works
String s = "foo"
println s.hashCode() // prints 22
println s.toString() // prints "foo"
Is toString somehow a special case (possibly for security reasons)?
See the first comment on this issue. It says about String's toString and other String related classes:
(...) seems to be intent, it is probably a
good idea to have a faster invocation
for classes that don't allow
overriding toString().
This is a know defect.
Basically Groovy does not correctly override methods that are part of an interface implementation.
This works:
class T {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
assert !t.doIt()
This doesn't:
interface I {
def doIt()
}
class T implements I {
def doIt() { true }
}
def t = new T()
assert t.doIt()
t.metaClass.doIt = { -> false }
assert !t.doIt()
Because toString() in String comes from CharSequence the correct way to override would be:
CharSequence.metaClass.toString = {-> "silly"}
println "hello world".toString()

Resources