2 September 2019
Useful function for inspect Java methods from Clojure
Problems
While working on Clojure project, you want to inspect the function from Java library and work with it effectively.
Solutions
We can write simple Clojure functions that make it easy to inspect and see available Java method/function at runtime (from the REPL or our favorite editor (Emacs/Vim/Cursive/etc))
(ns b12n.swiza.interops.core
(:require
[clojure.pprint :refer [pprint print-table]]
[clojure.reflect :refer [reflect]]))
;; Inspired by: https://gist.github.com/Sh4pe/eea52891dbeca5d0614d
(defn java-methods
[object]
(let [result (->> (reflect object)
:members
(filter :return-type)
(sort-by :name)
(map #(select-keys % [:flags :return-type :name :parameter-types])))]
result))
(defn jmethods
[object & [{:keys [show-public?
short-format?
show-getter?
show-setter?
show-private?]
:or {show-public? true
short-format? true
show-getter? false
show-setter? false
show-private? false}}]]
(let [result (java-methods object)]
(as-> result $
;; include public methods if one specified
(if show-public? (filter #(contains? (:flags %) :public) $) $)
;; include private methods if one specified
(if show-private? (filter #(contains? (:flags %) :private) $) $)
;; include getter methods if one specified
(if show-getter? (filter #(clojure.string/starts-with? (:name %) "get") $) $)
;; include setter methods if one specified
(if show-setter? (filter #(clojure.string/starts-with? (:name %) "set") $) $)
;; Finally print out the signature of the class
(if short-format?
;; print the function name once when it takes more than one way
(-> (map #(:name %) $) set seq)
(map #(format "%s %s %s(%s)"
(clojure.string/join " " (map name (:flags %)))
(:return-type %)
(:name %)
(clojure.string/join " " (map str (:parameter-types %)))) $)))))
(defn print-methods
"Print the method of a given Java class.
Examples:
(show-methods java.util.UUID) ;; see your REPL
(show-methods java.lang.String)"
[clazz]
(let [declared-methods (seq (:declaredMethods (bean clazz)))
methods (map #(.toString %) declared-methods)]
(doseq [m methods]
(println m))
methods))
Example Usages
- Using
print-methods
onjava.util.UUID
(print-methods java.util.UUID) ;; Reformat using pprint ;;=> ("public boolean java.util.UUID.equals(java.lang.Object)" "public java.lang.String java.util.UUID.toString()" "public int java.util.UUID.hashCode()" "public int java.util.UUID.compareTo(java.util.UUID)" "public int java.util.UUID.compareTo(java.lang.Object)" "public long java.util.UUID.timestamp()" "private static java.lang.String java.util.UUID.digits(long,int)" "public int java.util.UUID.version()" "public int java.util.UUID.variant()" "public static java.util.UUID java.util.UUID.randomUUID()" "public static java.util.UUID java.util.UUID.nameUUIDFromBytes(byte[])" "public static java.util.UUID java.util.UUID.fromString(java.lang.String)" "public long java.util.UUID.getLeastSignificantBits()" "public long java.util.UUID.getMostSignificantBits()" "public int java.util.UUID.clockSequence()" "public long java.util.UUID.node()")
- Using
jmethods
onjava.util.UUID
(jmethods java.util.UUID)
You will get
(compareTo
version
timestamp
randomUUID
nameUUIDFromBytes
fromString
getMostSignificantBits
getLeastSignificantBits
variant
toString
node
equals
hashCode
clockSequence)
If you just want to see the getter
methods only then you could use
(jmethods java.util.UUID {:show-getter? true})
Which should only show you the getter methods from the given Java class.
(getMostSignificantBits getLeastSignificantBits)
- Using
java-methods
onjava.util.UUID
(java-methods java.util.UUID)
Will give you something like:
({:flags #{:public},
:return-type int,
:name clockSequence,
:parameter-types []}
{:flags #{:public :bridge :synthetic},
:return-type int,
:name compareTo,
:parameter-types [java.lang.Object]}
{:flags #{:public},
:return-type int,
:name compareTo,
:parameter-types [java.util.UUID]}
{:flags #{:private :static},
:return-type java.lang.String,
:name digits,
:parameter-types [long int]}
{:flags #{:public},
:return-type boolean,
:name equals,
:parameter-types [java.lang.Object]}
{:flags #{:public :static},
:return-type java.util.UUID,
:name fromString,
:parameter-types [java.lang.String]}
{:flags #{:public},
:return-type long,
:name getLeastSignificantBits,
:parameter-types []}
{:flags #{:public},
:return-type long,
:name getMostSignificantBits,
:parameter-types []}
{:flags #{:public},
:return-type int,
:name hashCode,
:parameter-types []}
{:flags #{:public :static},
:return-type java.util.UUID,
:name nameUUIDFromBytes,
:parameter-types [byte<>]}
{:flags #{:public},
:return-type long,
:name node,
:parameter-types []}
{:flags #{:public :static},
:return-type java.util.UUID,
:name randomUUID,
:parameter-types []}
{:flags #{:public},
:return-type long,
:name timestamp,
:parameter-types []}
{:flags #{:public},
:return-type java.lang.String,
:name toString,
:parameter-types []}
{:flags #{:public},
:return-type int,
:name variant,
:parameter-types []}
{:flags #{:public},
:return-type int,
:name version,
:parameter-types []})
Personally I use jmethods
more often than others due to the ability to get specific value that I need via the options.
Hope this make your interactive development with Clojure easier and fun.
Links
- java.util.UUID Java documentation