No, I'd be perfectly happy with a command line tool that could analyse
my clojure program and tell me what imports I'm missing - I just don't
want to have to tediously go through the javadocs one by one and see,
for instance, that I need java.awt.Polygon but java.awt.geom.Point2D.
The reason I wondered if this were clojure-specific is that java
programs might well be easier to statically analyse than clojure ones.
I think his point is that if he gets an "Unable to resolve symbol:
Polygon" error and also an "Unable to resolve symbol: Point2D" error
then he still has to figure out which one is in java.awt and which is
in java.awt.geom. He wants a tool to spit out the list of required
imports so he doesn't have to remember exactly where they all are. If
there are conflicts, then the tool wouldn't have to guess. It could
just note the conflict for manual resolution.
--
Michael Wood <esio...@gmail.com>
I think his point is that if he gets an "Unable to resolve symbol:
Polygon" error and also an "Unable to resolve symbol: Point2D" error
then he still has to figure out which one is in java.awt and which is
in java.awt.geom. He wants a tool to spit out the list of required
imports so he doesn't have to remember exactly where they all are. If
there are conflicts, then the tool wouldn't have to guess. It could
just note the conflict for manual resolution.
This is far from complete and should be expanded but I got this from a
few hours of hacking:
(import '(java.util.jar JarFile JarEntry)
'(java.io File IOException))
(defn find-all
"(for [x coll :when (test-fn item (key-fn x))] x)"
([item coll test-fn key-fn]
(filter #(test-fn item (key-fn %)) coll))
([item coll test-fn]
(find-all item coll test-fn #'identity))
([item coll]
(find-all item coll #'= #'identity)))
(defn find-reg-in-seq
([reg coll key]
(find-all reg coll #'re-find key))
([reg coll]
(find-reg-in-seq reg coll #'identity)))
(defn dir-or-jar->seq
[path-entity]
(cond (instance? File path-entity)
(if (.isDirectory #^File path-entity)
(file-seq path-entity)
(throw (IOException. "Cannot search within a file.")))
(instance? JarFile path-entity)
(enumeration-seq (.entries #^JarFile path-entity))
true
(throw (UnsupportedOperationException.
(str "Cannot handle " (class path-entity))))))
(defn find-re-in-path-entity [reg path-entity]
(find-reg-in-seq reg
(dir-or-jar->seq path-entity)
#(.getName %)))
(defn find-class-in-path-entity [class-name path-entity]
(find-re-in-path-entity (re-pattern (str #"[^A-Za-z0-9$]" class-name
".class$"))
path-entity))
(def *rt-jar* (.toString
(File.
(File. (.getProperty System "java.home") "lib") "rt.jar")))
(defn find-java-class-in-classpath [class-name]
(let [cpath (cons *rt-jar* (.split (.getProperty System "java.class.path")
(.getProperty System "path.separator")))]
(mapcat #'identity
(filter #(not (nil? %))
(for [#^String path cpath]
(find-class-in-path-entity class-name
(if (.endsWith path ".jar")
(JarFile. path)
(File. path))))))))
(defn find-java-class [class-name]
(map (fn [o] (let [#^String s (.toString #^Object o)
l (.length s)]
(.. s (substring 0 (- l 6)) (replace "/" "."))))
(find-java-class-in-classpath class-name)))
;;; *eof*
It looks inside all jar files and at all .class files inside
directories in the classpath and rt.jar -- the java runtime library
and returns the list of classes that exist on the classpath.
I haven't written it inside a namespace etc. It's saved in a file
named "stuff.clj" because I couldnt' think of a good name.
user> (load "stuff")
nil
user> (find-java-class "List")
("com.sun.xml.internal.bind.v2.schemagen.xmlschema.List"
"java.awt.List" "java.util.List")
user> (find-java-class "URL")
("java.net.URL")
user> (find-java-class "NonExistent")
("com.sun.corba.se.impl.protocol.NonExistent")
user> (find-java-class "NonExistentClass")
nil
;; I never expected there'd be a class named "NonExistent" ;-)
The above code is released under public domain so anyone may do what
they wish with it.
Cheers
Vijay