起点将常规Servlet编码转换为我的DSL

Chi*_*ron 5 java macros dsl clojure jvm-languages

Clojure提供了一个很好的Java互操作.但是,我真的想拥有这个:

(servlet IndexServlet
  (service[parmas] ....)
  (do-post[params] ....)
  (do-get [params] ....))

(servlet-filter SecurityFilter
  (do-filter [params] ....))
Run Code Online (Sandbox Code Playgroud)

我猜这就是所谓的DSL,在Lisp世界中,它是通过宏完成的.

我不确定如何/从哪里开始.refiy和extends表单在这里肯定有重要作用,但我不知道它如何适合宏.

怎么开始做这个DSL?
一个片段,提示和技巧真的很感激.

Mic*_*zyk 3

您可能需要查看 Ring 的 Jetty 适配器,以获取 Clojure 中 servlet 实现的示例。源代码可在此处获取(链接到 1.1 版本的源代码)。特别是,该命名空间中定义的第一个函数proxy-handler返回一个基于 Jetty 提供的抽象类的处理程序。

如果您选择实现类似的方法(将您的 servlet 基于提供一些现成方法实现的 Java 类),您将需要使用proxy; 如果您只需要实现接口(没有子类化),那么您可能会想要reify替代。宏是否有用取决于实现的哪些部分将被修复;Ring 的 Jetty 适配器不会从宏的使用中受益,但您可以(例如,如果您希望将类扩展/接口实现为参数,如问题所示)。

无论如何,无论您选择实现哪个功能都需要成为接口或协议的一部分。因此,实施javax.servlet.Servlet附加操作foo可能如下所示:

(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]
    ...))
Run Code Online (Sandbox Code Playgroud)

然后,您可以将其包装在宏中以提供任何所需的语法糖。请注意,reify实际上并不关心在其主体内交错接口/协议名称和方法定义的方式,因此您可以让宏发出

(reify
  Servlet PFoo ... ; other interfaces & protocols
  (service [...] ...)
  (foo [...] ...)
  ;; other methods
  )
Run Code Online (Sandbox Code Playgroud)

如果这样更方便的话。

宏的草图,采用 servlet 接口的名称来实现(可能是扩展javax.servlet.Servlet)并使用一些额外的方法注入协议:

(defprotocol PFancyServlet
  (do-get [this ...])
  (do-post [this ...]))

(defmacro servlet [servlet-iface & meths]
   `(reify ~servlet-iface PFancyServlet
      ~@meths))
Run Code Online (Sandbox Code Playgroud)

meths需要包括do-getanddo-post以及servlet-iface方法;您可以添加一些参数验证以确保情况确实如此。调用示例:

(servlet SomeServletInterface
  (service [this ...] ...)
  ;; ...
  (do-get [this ...] ...)
  (do-post [this ...] ...))
Run Code Online (Sandbox Code Playgroud)