user12341234
user12341234

Reputation: 7213

Call series of Java static methods from Clojure

Let's say I have come across a class with several static setter methods that I'd like to call in a row. The functionality I'm looking for is similar to that provided by doto, except that it must work on a class instead of an object:

(doto MyClass
      (setA "a")
      (setB "b"))

Unfortunately, when I try this, I get RuntimeException: Unable to resolve symbol: setA. Is there a special doto macro for classes?

Upvotes: 2

Views: 418

Answers (2)

user12341234
user12341234

Reputation: 7213

I will leave this question open, since I'm hoping there's a better answer, but here's my home-grown macro to solve this problem:

(defmacro doto-class
  "Calls a series of static methods on a class"
  [klass & forms]
  (cons 'do
        (for [f forms]
          `(. ~klass ~f))))

which expands the example:

(macroexpand-1
 '(doto-class MyClass
              (setA "a")
              (setB "b")))

to

(do (. MyClass (setA "a"))
    (. MyClass (setB "b")))

Upvotes: 2

Thumbnail
Thumbnail

Reputation: 13473

How do you call a static Java method from Clojure? Like this ...

(Classname/staticMethod args*)

For example,

> (System/getProperty "java.vm.version")

=> "25.141-b15"

We want a macro, say doto-static, that re-arranges this from (doto-static System (getProperty "java.vm.version")), and also allows a chain of calls.

Such a macro is ...

(defmacro doto-static [class-symbol & calls]
  (let [qualify (fn [method-symbol] (->> method-symbol
                                    (name)
                                    (str (name class-symbol) \/)
                                  (symbol)))
        elaborate (fn [[method-symbol & arg-exprs]]
                      (cons (qualify method-symbol) arg-exprs))]
          (cons 'do (map elaborate calls))))

For example,

> (doto-static System (getProperty "java.vm.version") (getProperty "java.vm.version"))

=> "25.141-b15"

Upvotes: 1

Related Questions