Search code examples
javaclojureclasspathread-eval-print-loop

dynamicly add to classpath in clojure repl to access java class files (pomegranate/add-classpath)


I have compiled class files in shortScreen/out/production/classes/com/rsw/ and want to use them in a clojure repl. I think the hangup is on add-classpath but I'm unfamiliar with what should be happening. Or how to fix it.

(use '[cemerick.pomegranate :only (add-dependencies add-classpath)])
(import 'clojure.pprint)
(def myclasses "shortScreen/out/production/classes/com/rsw/")
; do i have the correct path?
(-> (clojure.java.io/file myclasses) (file-seq) (pprint)) ; shows many class files
(.exists (clojure.java.io/file myclasses "util.class")) ; true

; add the path
(add-classpath myclasses)

; but nothing like myclasses path in list
(def thiscp (.getURLs (java.lang.ClassLoader/getSystemClassLoader)))
(pprint thiscp)
(filter (fn [s] (re-seq #"out" s)) ;myclasses path should match "out"
     (for [x thiscp]
       (.toString x)))

; fails -- but not sure if this is the correct syntax anyway
(import 'com.rsw.util)
(util/msg "test")

Edit: A reproducible example

mkdir example && cd $_
# java code
cat > util.java << EOF
 package com.util;
 public class util {
 public static void msg(String a){
   System.out.println(a);
  }
 }
EOF

# clojure depends
cat > deps.edn << EOF
  {:deps {
    :alembic {:mvn/version "0.3.2"}
    :com.cemerick/pomegranate {:mvn/version "1.0.0"}
    }
  }
EOF

# compile java to class
javac util.java
ls # util.java util.class

# try to load in repl
clj

  (use '[cemerick.pomegranate :only (add-dependencies add-classpath)])
  (add-classpath (-> (java.io.File. ".") .getAbsolutePath))
  (import 'com.util.util)
  ; ClassNotFoundException com.util  java.net.URLClassLoader.findClass (URLClassLoader.java:381)

Solution

  • This question is old but as there are no accepted answers I figured it might be worth a response.

    The java classloader system uses the classpath as a set of search roots and expects to find the actual classes under:

    <classpath element>/<directory hierarchy representing package name>/<class name>.class

    which in your case would look something like this:

    example
    └── com
        └── util
            ├── Util.class
            └── Util.java
    

    i.e. it seems that in your example you are trying to load class com.util.util but putting the actual .class file in the root rather than under the appropriate directory hierarchy representing the com.util package name.

    I ran your reproducible example and after this change things seem to work:

    (import '[com.util Util])
    
    => com.util.Util
    

    (I upper cased the class name, otherwise I ran your example as is)