Is it possible to replace groovy method for existing object?

前端 未结 3 1770
终归单人心
终归单人心 2020-12-31 01:48

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         


        
相关标签:
3条回答
  • 2020-12-31 02:08

    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

    0 讨论(0)
  • 2020-12-31 02:11

    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.

    0 讨论(0)
  • 2020-12-31 02:27

    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.

    0 讨论(0)
提交回复
热议问题