frank
frank

Reputation: 511

Clojure call to static Java method of anonymous class

I have a set of Java classes that all implement the newBuilder interface (they are actually protobuf generated classes). I would like to pass the class as a parameter to a form that returns a function to create a new builder for that class.

(defn create-message-builder
  [klass]
  (. klass newBuilder))

I cannot get the form dynamically so that it calls the newBuilder static method on klass.

I found a macro on another SO post and made some modifications to support injecting it into my source:

(defmacro jcall [obj & args]
  `(let [ref (if (and (symbol? ~obj) 
                     (instance? Class (eval ~obj)))
          (eval ~obj)
          ~obj) ]
  (. ref# ~@args)))

When I attempt to call this macro:

repl> (jcall Contact newBuilder)
#object[com.skroot.Contact$Builder 0x5622de90 ""]

I get an error:

IllegalArgumentException No matching field found: newBuilder for class java.lang.Class

Upvotes: 0

Views: 400

Answers (1)

amalloy
amalloy

Reputation: 91837

The same thing you would do in Java: use reflection to ask the Class object what methods it has, find the one of the right name, and call it with no arguments.

(defn class->builder [c]
  (let [m (.getDeclaredMethod c "newBuilder" (into-array Class []))]
    (.invoke m nil (into-array Object []))))

Upvotes: 4

Related Questions