Пространство имен clojure.reflect
содержит методы для получения информации о классе. Я не думаю, что он даст вам имена параметров, хотя. Но вы можете использовать его для реализации чего-то, близкого к тому, что вы запрашиваете:
(ns playground.reify
(:require [clojure.reflect :as r])
(:import EWrapper))
(defn kebab-case [s]
;; TODO
s)
(defn arg-name [index]
(symbol (str "arg" index)))
(defn generate-method [member this cb]
(let [arg-names (mapv arg-name (range (count (:parameter-types member))))
method-name (:name member)]
`(~method-name [~this ~@arg-names]
(~cb {:type ~(keyword (kebab-case method-name))
:args ~arg-names}))))
(defmacro reify-ewrapper [this cb]
`(reify EWrapper
~@(map #(generate-method % this cb) (:members (r/reflect EWrapper)))))
(defn create [cb]
(reify-ewrapper this cb))
Вызов макроса reify-ewrapper расширится до
(reify*
[EWrapper]
(accountSummary
[this arg0 arg1 arg2 arg3 arg4]
(cb {:args [arg0 arg1 arg2 arg3 arg4], :type :accountSummary}))
(accountSummaryEnd
[this arg0]
(cb {:args [arg0], :type :accountSummaryEnd})))
Чтобы получить правильные имена параметров, вам, вероятно, придется проанализировать исходный Java исходный код, я не думаю, что они сохраняются в байтовом коде.
Расширенное решение с именами параметров
Если вам действительно нужны имена параметров, вот небольшой анализатор, который извлечет их. Сначала вам необходимо clojure.string :as cljstr
:
(defn parse-method [[name-str arg-str]]
(let [arg-sliced (subs arg-str 0 (cljstr/index-of arg-str ")"))
param-pairs (for [p (cljstr/split arg-sliced #",")]
(into []
(comp (map cljstr/trim)
(remove empty?)
(map symbol))
(cljstr/split p #" ")))]
{:name (symbol (subs name-str (inc (cljstr/last-index-of name-str " "))))
:parameter-types (mapv first param-pairs)
:parameter-names (mapv second param-pairs)}))
(defn parse-interface [s]
(map parse-method (partition 2 1 (cljstr/split s #"\("))))
Соответствующие биты кода для вывода имен параметров теперь выглядят так:
(defn generate-method [member this cb]
(let [arg-names (:parameter-names member)
method-name (:name member)]
`(~method-name [~this ~@arg-names]
(~cb ~(merge {:type (keyword (kebab-case method-name))}
(zipmap (map (comp keyword kebab-case str)
arg-names)
arg-names))))))
(defmacro reify-ewrapper [this cb]
`(reify EWrapper
~@(map #(generate-method % this cb) (parse-interface (slurp "javasrc/EWrapper.java")))))