java - 将常规 Servlet 编码转变为我的 DSL 的起点

标签 java macros clojure dsl jvm-languages

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

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

(servlet-filter SecurityFilter
  (do-filter [params] ....))

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

我不确定如何/从哪里开始。 refiy 和 extends 形式在这里肯定有重要作用,但我不知道这将如何适应宏。

如何开始做这个 DSL?
非常感谢一个片段、提示和技巧。

最佳答案

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

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

在任何情况下,无论您选择实现哪个功能,都需要成为接口(interface)或协议(protocol)的一部分。因此,实现 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]
    ...))

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

(reify
  Servlet PFoo ... ; other interfaces & protocols
  (service [...] ...)
  (foo [...] ...)
  ;; other methods
  )

如果那样更方便的话。

宏草图采用 servlet 接口(interface)的名称来实现(大概扩展 javax.servlet.Servlet)并注入(inject)带有一些额外方法的协议(protocol):

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

(defmacro servlet [servlet-iface & meths]
   `(reify ~servlet-iface PFancyServlet
      ~@meths))

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

(servlet SomeServletInterface
  (service [this ...] ...)
  ;; ...
  (do-get [this ...] ...)
  (do-post [this ...] ...))

关于java - 将常规 Servlet 编码转变为我的 DSL 的起点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16884878/

相关文章:

以下 C 宏会导致问题吗?

c++ - 如何在编译时在初始化列表中包含不同数量的对象?

c++ - __func__ 未在预处理输出中替换

clojure - 当一个符号被另一个符号引用时如何访问该符号的值

clojure - 为什么这个递归函数将一个空集合传递给 `take` ?

java - 为什么我不断收到对 ResultSet 进行非法操作的异常?

java - 使用 Java 的 HttpUrlConnection PATCH 请求

java - 让计时器从日期开始计数

从 amqp 客户端到 rabbitmq 服务器的 Java 8 SSL 握手失败

clojure - 持久收集是垃圾收集吗?