0

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

1
  • 1
    Also it's not an anonymous class at all. You just don't know its name at compile time because you're passed a Class object at runtime. Commented Jun 27, 2017 at 1:39

1 Answer 1

4

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 []))))
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.