Tricky uses of Clojure gen-class and AOT compilation
Today I was trying to figure out how to use Clojure to generate a class that would override certain methods of the parent class based on either:
The number of arguments (cardinality) of the method; or
The types of the arguments
It took a little bit of figuring out so I thought I'd write something down for Google to find.
Overriding methods based on cardinality
For this I found I could use multiple arguments forms as desired. Using a proxy:
(def *reader*
(proxy [java.io.StringReader] ["hello world"]
(read ([] (proxy-super read))
([x y z] 456))))
I can override the implementation of read
with three arguments while
passing the no-argument version back to the parent:
user=> (. *reader* read)
104
user=> (. *reader* (read (make-array Character/TYPE 5) 0 2))
456
We can do this using gen-class
too:
;; Note the tricky use of exposes-methods: this allows you to expose
;; the methods of the parent class under a different name.
(ns net.dishevelled.TestReader
(:gen-class :extends java.io.StringReader
:exposes-methods {read readSuper}))
(defn -read
([this] (. this readSuper))
([this cbuf off len] 456))
Overriding methods based on type signature
I couldn't see a way of doing this using a proxy, but here's how you can override a method based on the types of its arguments:
(ns net.dishevelled.TestReader
(:gen-class :extends java.io.StringReader))
;; gen-class looks for a method with argument types in its name for
;; overriding specific method signatures. The char<> syntax for
;; primitive array types took me a little bit to figure out...
(defn -read-char<>-int-int [this cbuf off len]
456)
and we can override a method which takes no arguments by giving its type
as void
:
(defn -read-void [this]
456)