Braintree Java 라이브러리 용 Clojure 래퍼를 작성하여보다 간결하고 관용적 인 인터페이스를 제공합니다. 내가 this question 같이 내가 명시 적으로이 작업을 수행 할 수 있습니다 알고지도를 기반으로 Java setter를 호출하기위한 Clojure 매크로?
(transaction-request :amount 10.00 :order-id "user42")
: 나는 자바처럼, 신속하고 간결 객체 인스턴스화하는 기능을 제공하고 싶습니다
(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-from-map
의 매크로 버전을 정의하려고 시도했지만 매크로가 충분하지 않습니다. 설명 된대로 eval
이 필요합니다. here.
리플렉션을 사용하지 않고 런타임에 지정된 Java 메소드를 호출하는 방법이 있습니까?
미리 감사드립니다.
업데이트 된 솔루션 :
주스의 조언에 따라, 나는 유사한 기술을 사용하여 문제를 해결할 수 있었다. 매크로는 컴파일시에 리플렉션을 사용하여 클래스가 가지고있는 setter 메소드를 식별 한 다음 폼에서 spam을 검사하여 맵에서 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]
[email protected](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
))
을 선호하는 것이 아니다 반사? 거의 확실하지 않습니다. –
글쎄, 매크로를 사용하여 맵을 reflection_without없이 메소드 호출로 변환 할 수 있습니다. 매크로가 맵을 포함하는 기호를 사용할 수는 없지만 원시 맵 자체 만 사용할 수 있다는 것을 깨닫고 리플렉션을 사용했습니다. 아마도 @runtime_에서의 반사를 피하고 싶습니다. @ joost-diepenmaat은 아래에서 설명합니다. – bkirkbri