views:

105

answers:

1

While using Clojure proxies, fns passed to proxy should override existing methods or are they called in conjunction with super.method()?

In the following code, RequestHandler.get() is invoked along with the proxy get [].

;see: http://github.com/paulosuzart/JTornado
(ns org.ctornadoweb)
(import '(org.jtornadoweb Web$RequestHandler))
(import '(org.jtornadoweb HttpServer Web$Application))


(let [myHandler (proxy [Web$RequestHandler] [] 
                  (get [] 
                    (.write "Hi CLJ"))
                  (post []
                    (.write "POST")))]

(.listen
  (HttpServer.  
    (.add (Web$Application.) "/" (class myHandler))
    false nil false) 8089))

The same happens to the compiled/inheritance version:

; Starts a JTornado HTTP Server and a sample RequestHandler.
; Bit verbose due to compilation directives. Recommendation is to generate 
; a set of macros to hide this.
(ns org.ctornadoweb
; Compiled and implements a static main method to start the server
  (:import (org.jtornadoweb HttpServer)
           (org.jtornadoweb.Web$Application)
           (org.jtornadoweb.Web$RequestHandler))
  (:gen-class :prefix "server-"))

(gen-class
 :name org.ctornadoweb.MyHandler
 :extends org.jtornadoweb.Web$RequestHandler
 :prefix "do")

(defn do-get [this]
  "Handles the HTTP GET method"
  (.write "hello clojure"))
(defn do-post [this]
  "Handles the HTTP POST method"
  (.write (.getArgument "name" "default" false)))


(defn server-main []
  "main method"
 (.listen
  (org.jtornadoweb.HttpServer.
   (.add (org.jtornadoweb.Web$Application.) "/" org.ctornadoweb.MyHandler)
     false nil false) 8089))

;use (compile 'org.ctornadoweb)

The trace shows the proxy get being invoked and then the super.get, what throws (by default) an exception.

HTTP 405: Method Not Allowed 
    at org.jtornadoweb.Web$RequestHandler.get(Web.java:72)
    at org.ctornadoweb.proxy$org.jtornadoweb.Web$RequestHandler$0.get(Unknown Source)

I tried to find some words about the actual behavior of Clojure Proxies. Can someone give this help?

+7  A: 

No, the super method will not be called automatically, though you can explicitly call it with proxy-super.

The following test case shows things working as they should:

user=> (def foo 
         (proxy [java.util.ArrayList] [] 
           (clear [] (println "not clearing"))))
#'user/foo
user=> (.size foo)
0
user=> (.add foo "hi")
true
user=> (.add foo "bye")
true
user=> (.size foo)
2
user=> (.clear foo)
not clearing
nil
user=> (.size foo)
2

If super.clear() were getting called, the size would show as 0.

Alex Taggart