Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clojure: import java class dynamically

Tags:

java

clojure

Suppose I define such clojure function:

(defn print-this [this] (println "print this: " this))

If I use the function in repl:

(print-this that)

I would end up with:

print this: that
nil

as output.

Now if I make such definition:

(defn import-by-name [name] (import (some.package.value name)))

and use the function in repl:

(import-by-name "SomeClassName")

I get

java.lang.ClassNotFoundException: some.package.value.name (NO_SOURCE_FILE:0)

where I would expect that "name" be replaced by "SomeClassName" instead. If I type:

(import (some.package.value SomeClassName))

everything works as expected.

Why is it that [name] is not interpreted in the import-by-name function above? Is it possible to dynamically import a java class from a variable value? If so how? thanks!

like image 379
Sebastien Avatar asked Oct 08 '13 19:10

Sebastien


1 Answers

import is a macro, so any symbols you pass to it will be taken literally.

(macroexpand '(import (some.package.value name)))

;; => (do (clojure.core/import* "some.package.value.name"))

Literals

For string literals, and by extension collection literals, you can use a macro to accomplish what you are describing.

(defmacro import-by-name [name] `(import '[some.package.value ~name]))

(import-by-name "ClassName") ;; => nil

Vars

For importing classes from a var, you have to start dipping into the internals of namespaces.

(defn import-by-name [n]
  (.importClass (the-ns *ns*)
                (clojure.lang.RT/classForName (str "some.package.value." n))))

There might be a cleaner way, and I will update this answer if I find one.

like image 146
Jared314 Avatar answered Sep 20 '22 07:09

Jared314