Reputation: 14258
I wish to write a function that interops with java objects
(assoc-obj <object> "<Prop1>" <Val1> "<Prop2>" <Val2>)
which is the same as
(doto <object>
(.set<Prop1> <Val1>)
(.set<Prop2> <Val2>))
I'm working with reflection:
(let [method (->>
(seq (.getMethods java.util.Date))
(filter #(= "setDate" (.getName %)))
first)
arr (object-array 1)
_ (aset arr 0 (int 1))
d (java.util.Date.)]
(.invoke method d arr)
d)
but I am finding that there are problems with type coercing.
Are there better/more clojurish ways of doing this?
Upvotes: 0
Views: 103
Reputation: 33637
It seems like a simple code transformation by looking at the example you have shown, so why not a macro:
(defmacro assoc-obj [obj & props]
(let [psets (map (fn [[p v]] (list (symbol (str ".set" p)) v ))
(partition 2 props))]
`(doto ~obj ~@psets)))
Upvotes: 1
Reputation: 84331
I'd use clojure.lang.Reflector/invokeInstanceMethod
. Here's a REPL demo:
user=> (def d (java.util.Date.))
#'user/d
user=> d
#inst "2013-12-04T05:47:33.560-00:00"
user=> (clojure.lang.Reflector/invokeInstanceMethod
d "setDate" (object-array (list 1)))
nil
user=> d
#inst "2013-12-01T05:47:33.560-00:00"
I'd consider everything about the reflector is an implementation detail (tweaks to method signatures might happen occasionally etc.), but this functionality is necessary in Clojure, in one form or another.
Upvotes: 1