1

I'm playing with Groovy and I wonder, why doesn't this piece of code works?

package test

interface A {
    void myMethod()
}

class B implements A {
    void myMethod() {
        println "No catch"
    }
}

B.metaClass.myMethod = {
    println "Catch!"
}

(new B()).myMethod()

It prints out No catch, while I expect it to print Catch! instead.

Alex Abdugafarov
  • 6,112
  • 7
  • 35
  • 59

3 Answers3

9

It's a bug in Groovy, there is an open issue in JIRA: Cannot override methods via metaclass that are part of an interface implementation, GROOVY-3493.

brunobowden
  • 1,492
  • 19
  • 37
Arturo Herrero
  • 12,772
  • 11
  • 42
  • 73
1

Instead of rewriting B.metaClass.myMethod, try following:

 B.metaClass.invokeMethod = {String methodName, args ->
    println "Catch!"
 }

This blog post describes it quite well.

Anton Arhipov
  • 6,479
  • 1
  • 35
  • 43
0

There is a workaround but it only applies to all classes and not specific instances.

metaclass modification BEFORE construction:

interface I {
    def doIt()
}

class T implements I {
    def doIt() { true }
}

I.metaClass.doIt = { -> false }
T t = new T()
assert !t.doIt()

metaclass modification AFTER construction:

interface I {
    def doIt()
}

class T implements I {
    def doIt() { true }
}

T t = new T()
// Removing either of the following two lines breaks this
I.metaClass.doIt = { -> false }
t.metaClass.doIt = { -> false }
assert !t.doIt()
brunobowden
  • 1,492
  • 19
  • 37