Hello,
I have been struggling with this for some hours now and would welcome some pointers. I'm writing a small how-to on how to deploy Common Lisp web applications (i.e. "something that replies to an HTTP request") in IBM's Bluemix using ABCL. That part is taken care of and I have it up and running (more on that in a separate post). I was going for a more advanced version and I am having a problem with interface implementation.
To showcase java interop I am not using CL web frameworks, but decided to give Spark a try (http://sparkjava.com/documentation.html) just to get a minimal example up and running (I already have Jetty working and serving up an "(Hello World)" page):
#+BEGIN_SRC java import static spark.Spark.*;
public class HelloWorld { public static void main(String[] args) { get("/hello", (req, res) -> "Hello World"); } } #+END_SRC
I'm going to start with the Clojure example since that one I got working; the API reference (http://spark.screenisland.com/spark/Spark.html) helped me and this works
#+BEGIN_SRC clojure => (Spark/get "/hello" (reify spark.Route (handle [this req res] ("Hello World")))) [Thread-34] INFO spark.webserver.JettySparkServer - == Spark has ignited ... [Thread-34] INFO spark.webserver.JettySparkServer - >> Listening on 0.0.0.0:4567 nil[Thread-34] INFO org.eclipse.jetty.server.Server - jetty-9.3.2.v20150730 #+END_SRC
I have learned (thanks to bpalmer in #emacs, cheers!) that the Single Abstract Method can be constructed using Java 8 lambda expressions, which is why I couldn't find a reference to the "handle" method, which I got from the API.
Now, back to ABCL; I'm unable to reproduce the above and I'm unsure if it is because I'm not getting something right (likely) or because some of the plumbing in ABCL isn't quite there yet.
I tried this using jss::jinterface-implementation (which I had used previously with my MQTT code and worked perfectly):
#+BEGIN_SRC lisp (#"get" 'spark.Spark "/hello" (jss::jinterface-implementation "spark.Route" "handle" (lambda (request response) ("Hello World")))) #+END_SRC
The (jinterface-implementation ...) returns #<com.sun.proxy.$Proxy5 com.sun.proxy.$Proxy5@4f0bbf2a {41CC48BB}>, but the (#"get"...) fails:
Java exception 'java.lang.NoClassDefFoundError: Could not initialize class spark.Spark$SingletonHolder'.
I have also tried with jmake-proxy to see if there was something different going on.
#+BEGIN_SRC lisp (java::jstatic "get" "spark.Spark" "/hello" (java::jmake-proxy "spark.Route" #'(lambda (lisp-this method request response) ("Hello World")))) #+END_SRC
The result is the same, both in what jmake-proxy returns and the final error. Note that I have added the jar to the classpath, otherwise I would get "ClassNotFound".
Even more simply this also doesn't work:
#+BEGIN_SRC clojure => (Spark/stop) [nREPL-worker-11] INFO spark.webserver.JettySparkServer - >>> Spark shutting down ... #+END_SRC
... (#"stop" 'spark.Spark) returns the same "NoClassDefFoundError", which makes me thing the issue is not with the jproxy bit but something more fundamental...
With this in mind:
1) Is there anything obviously wrong about the way I'm going about it - not limited to implementation errors on my part but including trying to use parts of ABCL's Java interop which aren't done?
2) The java::jmake-proxy call... I wasn't able to find a single example of it used (the only code I find when searching is the implementation itself) so I'm not sure I'm understanding the documentation correctly: are the arguments I'm using above correct? I'm using the method that uses a function and if I understood it correctly the first argument is "lisp-this" (which defaults to nil), the second the method name (which would be "handle" in this example, and the rest are the method arguments (request and response here).
I am of course available for any further clarification, and if this is something that isn't obvious I can upload a minimal example using quickproject and quicklisp.
Best regards,