The following code tried to replace an existing method in a Groovy class:
class A {
void abc() {
println \"original\"
}
}
x= new A()
x.abc()
A.me
You can use the per-instance metaClass to change the value in the existing object like so:
x= new A()
x.abc()
x.metaClass.abc={-> println "new" }
x.abc()
x.metaClass.methods.findAll{it.name=="abc"}.each { println "Method $it"}
But as you have seen, x will have two methods associated with it (well, in actual fact, a method and the closure you added
If you change the definition of A so that the method becomes a closure definition like so:
class A {
def abc = { ->
println "original"
}
}
Then you will only get a single closure in the metaClass and no method after the alteration
I fully agree with @tim_yates on this. But, there is a way around, if you want to avoid modifying the original class use MethodClosure instead, as shown below:
class A {
void abc() {
println "original"
}
}
x = new A()
//Create a Method Closure or Method pointer
pointer = x.&abc
//Replace Original call with Method pointer
//x.abc()
pointer()
//Meta classed
A.metaClass.abc={-> println "new" }
//Call method pointer instead of original again
//x.abc()
pointer()
A.metaClass.methods.findAll{it.name=="abc"}.each { println "Method $it"}
new A().abc()
You should get what is expected:
original
new
Method org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod@43094309
[name: abc params: [] returns: class java.lang.Object owner: class A]
Method public void A.abc()
new
Based on Groovy 2.2.1. The question is too old though.
I'm sure your still having this issue ;) but... I'm running Groovy version 1.8.7 on Fedora 17. I've found that have you have to do this combination:
A.metaClass.abc = {-> println it}
A obj = new A()
obj.metaClass.abc = {-> println it}
obj.abc
From there on out it will act as you want. When you look for the methods, you'll still get two:
Method org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod@103074e[name: abc params: [] returns: class java.lang.Object owner: class A]
Method public void A.abc()
But at least you don't have to change your public void
declaration.
Not sure if this is a bug or what.