用于根据地图调用Java设置器的Clojure宏?
发布时间:2020-05-27 06:51:37 所属栏目:Java 来源:互联网
导读:我为Braintree Java库编写了一个Clojure包装器,以提供更简洁和惯用的界面.我想提供功能来快速简洁地实例化Java对象,如: (transaction-request :amount 10.00 :order-id user42) 我知道我可以明确地做到这一点,如this question所示: (defn transaction-reque
|
我为Braintree Java库编写了一个Clojure包装器,以提供更简洁和惯用的界面.我想提供功能来快速简洁地实例化Java对象,如: (transaction-request :amount 10.00 :order-id "user42") 我知道我可以明确地做到这一点,如this question所示: (defn transaction-request [& {:keys [amount order-id]}]
(doto (TransactionRequest.)
(.amount amount)
(.orderId order-id)))
但是,对于许多类来说这是重复的,当参数是可选的时,它变得更加复杂.使用反射,可以更简洁地定义这些功能: (defn set-obj-from-map [obj m]
(doseq [[k v] m]
(clojure.lang.Reflector/invokeInstanceMethod
obj (name k) (into-array Object [v])))
obj)
(defn transaction-request [& {:as m}]
(set-obj-from-map (TransactionRequest.) m))
(defn transaction-options-request [tr & {:as m}]
(set-obj-from-map (TransactionOptionsRequest. tr) m))
显然,如果可能,我想避免反思.我试图定义一个宏映射的set-obj从地图,但我的宏夫不够强大.这可能需要eval,如here所述. 有没有办法调用在运行时指定的Java方法,而不使用反射? 提前致谢! 更新解决方案: 根据Joost的建议,我能够使用类似的技术来解决问题.一个宏在编译时使用反射来识别类有哪些setter方法,然后在表中查找param,并用该值调用该方法. 这里是宏和一个例子: ; Find only setter methods that we care about
(defn find-methods [class-sym]
(let [cls (eval class-sym)
methods (.getMethods cls)
to-sym #(symbol (.getName %))
setter? #(and (= cls (.getReturnType %))
(= 1 (count (.getParameterTypes %))))]
(map to-sym (filter setter? methods))))
; Convert a Java camelCase method name into a Clojure :key-word
(defn meth-to-kw [method-sym]
(-> (str method-sym)
(str/replace #"([A-Z])"
#(str "-" (.toLowerCase (second %))))
(keyword)))
; Returns a function taking an instance of klass and a map of params
(defmacro builder [klass]
(let [obj (gensym "obj-")
m (gensym "map-")
methods (find-methods klass)]
`(fn [~obj ~m]
~@(map (fn [meth]
`(if-let [v# (get ~m ~(meth-to-kw meth))] (. ~obj ~meth v#)))
methods)
~obj)))
; Example usage
(defn transaction-request [& {:as params}]
(-> (TransactionRequest.)
((builder TransactionRequest) params)
; some further use of the object
))
解决方法你可以在编译时使用反射只要你知道你正在处理的类,然后找出字段名称,并从中生成“静态”设置器.我写了一些代码,对于getter来说,你可能会发现有趣的.见 https://github.com/joodie/clj-java-fields(特别是 https://github.com/joodie/clj-java-fields/blob/master/src/nl/zeekat/java/fields.clj中的def-fields宏).(编辑:安卓应用网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
