Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get something like an anonymous inner class in Groovy?

Tags:

groovy

How do I define an anonymous inner class in Groovy? I saw references that they were supposed to be supported in Groovy 1.7 and I'm using 1.8.

 thread = process.consumeProcessOutput(
   new Appendable() {
     Appendable append(char c) {
       app1.append(c)
       app2.append(c)
       return this
     }

     Appendable append(CharSequence csq) {
       app1.append(csq)
       app2.append(csq)
       return this
     }

     Appendable append(CharSequence csq, int start, int end) {
       app1.append(csq, start, end)
       app2.append(csq, start, end)
       return this
     }
   })

I get an exception with this code:

Caught: groovy.lang.MissingMethodException: No signature of method: java.lang.UNIXProcess.consumeProcessOutput() is applicable for argument types: (MyClass$1) values: [MyClass$1@19c8ef56]
like image 656
dromodel Avatar asked Oct 25 '11 20:10

dromodel


1 Answers

This is a tricky case since the methods have to return the object itself as an Appendable, and has an overloaded method name that doesn't work well with groovy map to interface casting. The simplest, clearest way is probably to just use an anonymous inner class, as you would in Java. This requires a reasonably current version of groovy (1.7 or newer I think):

def testAppendable(Appendable appendable) {
    println "appendable = $appendable"
    appendable.append('a' as char).
               append('b' as char).
               append('c' as char)
}

testAppendable(new Appendable() {
    Appendable append(char c) {
        println "got $c"
        this
    }
    Appendable append(CharSequence csq) {
        this
    }
    Appendable append(CharSequence csq, int start, int end) {
        this
    }
    String toString() { "inner class appendable" }
});

Another alternative would be to use an Expando with closures. It's a bit awkward since only one implementation per method name can be initialized in the constructor. Note that any interface methods omitted are given a default implementation that throws an exception.

testAppendable(new Expando(
    append: { char c ->
        println "got $c"
        delegate as Appendable
    },
    toString: { ->
        "expando appendable"
    }
) as Appendable)

EDIT: Regarding your example, I don't see why it would fail. My test is almost identical and works without any issues. What does the signature of process.consumeProcessOutput look like? Also, you can double check that MyClass$1 implements Appendable by running javap MyClass$1.

like image 192
ataylor Avatar answered Oct 03 '22 22:10

ataylor