Edgar Espina Edgar Espina - 1 month ago 12
Groovy Question

Groovy: Ambiguous method overloading for method

I'm struggling with

groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method
exception in groovy-2.4.7.

I have 3 functional interfaces:

interface NoArg {
Object handle();
}
interface OneArg {
Object handle(Request req);
}
interface TwoArg {
Object handle(Request req, Response rsp);
}


There is an App.java which provides some
overloaded
methods like:

public class App {
void get(String pattern, NoArg handler) {
...
}
void get(String pattern, OneArg handler) {
...
}
void get(String pattern, TwoArg handler) {
...
}
}


From Java I can make calls like:

{
get("/", () -> "OK");
get("/", req -> "OK");
get("/", (req, rsp) -> rsp.send("OK"));
}


It works perfectly in Java, but I got an
Ambiguous method overloading for method
in Groovy when I just try:

{
get("/", {-> "OK"})
}


Here is the full stacktrace:

21:34:13.502 [ERROR] [system.err] groovy.lang.GroovyRuntimeException: Ambiguous method overloading for method app.App#get.
21:34:13.502 [ERROR] [system.err] Cannot resolve which method to invoke for [class java.lang.String, class app.App$_closure1] due to overlapping prototypes between:
21:34:13.502 [ERROR] [system.err] [class java.lang.String, interface app.NoArg]
21:34:13.502 [ERROR] [system.err] [class java.lang.String, interface app.OneArg]
21:34:13.502 [ERROR] [system.err] [class java.lang.String, interface app.TwoArg]


Am I missing something? Or this isn't supported in Groovy?

Thanks.

Answer

I ended up writing an extension module:

/**
 * Example on how to hack Groovy so we can use groovy closure on script routes.
 */
class AppExtension {

  private static Object toHandler(Closure closure) {
    if (closure.maximumNumberOfParameters == 0) {
      NoArg handler = { closure() }
      return handler
    } else if (closure.maximumNumberOfParameters == 1) {
      OneArg handler = { req -> closure(req) }
      return handler
    }
    TwoArg handler = { req, rsp -> closure(req, rsp) }
    return handler
  }

  static void get(App self, String pattern, Closure closure) {
    self.get(pattern, toHandler(closure));
  }

  static void post(App self, String pattern, Closure closure) {
    self.get(pattern, toHandler(closure));
  }
}

I created a generic get method that accepts a Closure. Then I checked for closure parameters and convert the closure to the required interface.