Gangmax Blog

自由之思想,独立之精神

Groovy Closure Gets MissingMethodException When Accessing Private Methods in Super Class

| Comments

I encounter the following problem today when using Groovy closure with class inheritance involved:

  1. The base class “BaseClass” has a protected method “doA”, in which it has a method invocation which takes a closure as argument. In that closure, a private method “doB” of “BaseClass” is used. This class works fine;

  2. Now a subclass of “BaseClass” is created as “SubClass”, it overrides “doA”. After some operations, it invokes “doA” in “BaseClass” as well. But at this moment, an “MissingMethodException” is thrown which complains “doB” cannot be found.

The following code works:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class NerdHandler {
    void handle(Closure c) {
        c.call('nerd')
    }
}

class BaseClass {
    void run() {
        doA()
    }

    protected void doA() {
        NerdHandler handler = new NerdHandler()
        handler.handle { nerd ->
            doB("Say hello to ${nerd}!")
        }
    }

    private void doB(String statement) {
        println(statement)
    }
}

BaseClass b = new BaseClass()
b.run()

But the following code gets ”MissingMethodException: No signature of method: SubClass.doB() is applicable for argument types: (org.codehaus.groovy.runtime.GStringImpl) values: [Say hello to nerd!]”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class NerdHandler {
    void handle(Closure c) {
        c.call('nerd')
    }
}

class BaseClass {
    void run() {
        doA()
    }

    protected void doA() {
        NerdHandler handler = new NerdHandler()
        handler.handle { nerd ->
            doB("Say hello to ${nerd}!")
        }
    }

    private void doB(String statement) {
        println(statement)
    }
}

class SubClass extends BaseClass {
    protected void doA() {
        println("zzz...")
        super.doA()
    }
}

SubClass s = new SubClass()
s.run()

However if you change the “private” to “protected” in line “19”(private void doB(String statement)), it works.

Someone else also reports this issue here and here.

From this error, it seems a Groovy closure’s context is not the class which defines it, but the one which triggers its invocation.

Comments