Reify in macro woes


#1

Hi…

Disclaimer: My macro skills are something I rarely exercis, so please bear with me :-).

When playing with helidon (http://helidon.io) today, I came up with this translation of their getting started sample:

(ns helidontry.core
  (:import (io.helidon.webserver WebServer Routing ServerResponse ServerRequest Handler ServerConfiguration)))

(defn -main [& args]
  (doto (WebServer/create
          (-> (ServerConfiguration/builder)
              (.port 8080)
              (.build))
          (-> (Routing/builder)
              (.get "/greet" (into-array
                               [(reify
                                  Handler
                                  (^void accept
                                    [^Handler this ^ServerRequest req ^ServerResponse res]
                                    (.send res "Hello World")))]))
              (.build)))
    (.start)))

The routing handler into-array/reify looks really ugly, so I thought I use a macro here.
This is what I came up with:

(defmacro helidon-handler [[this req res] & body]
  `(into-array
     [(reify Handler
        (~(with-meta 'accept {:tag 'void})
          [~(vary-meta this assoc :tag Handler)
           ~(vary-meta req assoc :tag ServerRequest)
           ~(vary-meta res assoc :tag ServerResponse)]
          [email protected]))]))

and use it like this:

...
                (.get "/greet" (helidon-handler [this req res]
                                                (.send res "Hello World")))
…

Looks much better IMHO, but unfortunately does not work.
The server starts up, but when exercising it with a

  (slurp "http://localhost:8080/greet")

I get an error:

java.lang.AbstractMethodError: Method helidontry/core$_main$reify__1500.accept(Lio/helidon/webserver/ServerRequest;Lio/helidon/webserver/ServerResponse;)V is abstract
	at helidontry.core$_main$reify__1500.accept(core.clj)
...

The reify did not create the correct access method signature it seems.

(set! *print-meta* true)
(macroexpand-1 '(helidon-handler [this req res]
                                 (.send res "Hello World")))

yields

(clojure.core/into-array
 [(clojure.core/reify
   io.helidon.webserver.Handler
   (^void accept
    [^io.helidon.webserver.Handler this
^io.helidon.webserver.ServerRequest req
^io.helidon.webserver.ServerResponse res]
^{:line 95, :column 34} (.send res "Hello World")))])

which looks ok to me.

When I paste this exact macro expansion ihto the code replacing the macro call, it works.

Any idea what is going wrong here?

Ciao

…Jochen