Clojure offers a good Java interop. However, I really want to have this:
(servlet IndexServlet
(service[parmas] ....)
(do-post[params] ....)
(do-get [params] ....))
(servlet-filter SecurityFilter
(do-filter [params] ....))
I guess that is what called a DSL and in Lisp world it is done via Macros.
I'm not sure how/where to start. refiy and extends forms are definitely have important role here but I don't know how that would fit into Macros.
How start doing this DSL?
A snippet, tips and tricks are really appreciated.
You may want to look into Ring's Jetty adapter for an example of a servlet implementation in Clojure. The source is available here (link to source for the 1.1 release). In particular, the first function defined in that namespace, proxy-handler
returns a handler based on an abstract class provided by Jetty.
If you choose to implement a similar approach (basing your servlet on a Java class providing some ready-made method impls), you'll need to use proxy
; if you only need to implement interfaces (with no subclassing), then you'll probably want reify
instead. Whether or not macros will be useful depends on which parts of the implementation will turn out to be fixed; Ring's Jetty adapter wouldn't benefit from the use of macros, but you may (for example if you wish to make the class to be extended / interface to be implemented into an argument, as the question seems to indicate).
In any case, whichever functionality you choose to implement will need to be part of an interface or protocol. So, implementing javax.servlet.Servlet
plus an additional operation foo
might look like this:
(import (javax.servlet Servlet ServletRequest ServletResponse))
(defprotocol PFoo
(foo [this x y z]))
(reify
Servlet
(service [this ^ServletRequest req ^ServletResponse res]
...)
;; other Servlet methods here...
PFoo
(foo [this x y z]
...))
You could then wrap this in a macro to provide any desired syntactic sugar. Note that reify
does not actually care about the way in which you interleave interface / protocol names and method definitions inside its body, so you could have your macro emit
(reify
Servlet PFoo ... ; other interfaces & protocols
(service [...] ...)
(foo [...] ...)
;; other methods
)
if that's more convenient.
A sketch of a macro taking a name of a servlet interface to implement (presumably extending javax.servlet.Servlet
) and injecting a protocol with some extra methods:
(defprotocol PFancyServlet
(do-get [this ...])
(do-post [this ...]))
(defmacro servlet [servlet-iface & meths]
`(reify ~servlet-iface PFancyServlet
~@meths))
meths
will need to include do-get
and do-post
as well as servlet-iface
methods; you could add some argument validation to make sure this is the case. An example call:
(servlet SomeServletInterface
(service [this ...] ...)
;; ...
(do-get [this ...] ...)
(do-post [this ...] ...))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With