创建使用字符串调用java函数的Clojure宏
因此,我正在尝试制作一个Clojure宏,它可以方便地利用构建器模式与Java类进行互操作 这是我到目前为止试过的创建使用字符串调用java函数的Clojure宏,clojure,macros,Clojure,Macros,因此,我正在尝试制作一个Clojure宏,它可以方便地利用构建器模式与Java类进行互操作 这是我到目前为止试过的 (defmacro test-macro [] (list (symbol ".queryParam") (-> (ClientBuilder/newClient) (.target "https://www.test.com")) "key1" (object-array ["val1"]))) 扩展到下面 (.
(defmacro test-macro
[]
(list
(symbol ".queryParam")
(-> (ClientBuilder/newClient)
(.target "https://www.test.com"))
"key1"
(object-array ["val1"])))
扩展到下面
(.
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget@107a5073"]
queryParam
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;@16751ba2"])
预期的结果是:
(.queryParam
#object[org.glassfish.jersey.client.JerseyWebTarget 0x107a5073 "org.glassfish.jersey.client.JerseyWebTarget@107a5073"]
"key1"
#object["[Ljava.lang.Object;" 0x16751ba2 "[Ljava.lang.Object;@16751ba2"])
我猜
导致了一些东西被评估和移动?在这种情况下,解决办法是引用它。但是如何引用计算表达式的结果呢
我的目标是将映射转换为代码,通过将映射键作为要调用的函数,将值作为传递到Java函数的参数来构建对象
我了解如何使用线程和do to宏,但我正在尝试使请求构建函数数据驱动。我希望能够接受一个映射,其中键为“queryParam”,值为参数。通过这样做,我可以充分利用java类函数的全部功能,只需自己编写一个函数,并且有足够的1对1映射,我不相信其他人会觉得这很神奇
(def test-map {"target" ["https://www.test.com"]
"path" ["qa" "rest/service"]
"queryParam" [["key1" (object-array ["val1"])]
["key2" (object-array ["val21" "val22" "val23"])]] })
(-> (ClientBuilder/newClient)
(.target "https://www.test.com")
(.path "qa")
(.path "rest/service")
(.queryParam "key1" (object-array ["val1"]))
(.queryParam "key2" (object-array ["val21" "val22" "val23"])))
从您的问题来看,还不清楚是否必须使用map作为构建器数据结构。我建议使用threading宏直接处理实现构建器模式的Java类:
(-> (ClientBuilder.)
(.forEndpoint "http://example.com")
(.withQueryParam "key1" "value1")
(.build))
对于未实现生成器模式的类及其方法返回void
(例如setter方法),可以使用doto
宏:
(doto (Client.)
(.setEndpoint "http://example.com")
(.setQueryParam "key1" "value1"))
使用映射对Java方法调用进行编码来实现宏是可能的,但很尴尬。您必须将每个方法参数保持在一个序列中(映射值中),以便能够调用具有多个参数的方法,或者具有存储单参数方法参数、处理varargs、,使用map来指定方法调用并不能保证调用顺序等。它会给代码增加很多复杂性和魔力
这是您可以实现它的方式:
(defmacro builder [b m]
(let [method-calls
(map (fn [[k v]] `(. (~(symbol k) ~@v))) m)]
`(-> ~b
~@method-calls)))
(macroexpand-1
'(builder (StringBuilder.) {"append" ["a"]}))
;; => (clojure.core/-> (StringBuilder.) (. (append "a")))
(str
(builder (StringBuilder.) {"append" ["a"] }))
;; => "a"