简体   繁体   中英

how to invoke a setter method on an object (that coerces types)

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?

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.

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)))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM