librelist archives

« back to archive

Issues getting leiningen-core to work with Java interop

Issues getting leiningen-core to work with Java interop

From:
Jan Thomä
Date:
2012-08-23 @ 19:44
Hi,

I'm the maintainer of the Leiningen Plugin for IntelliJ and I'm 
currently trying to use leiningen-core to parse the project files and 
resolve the dependencies instead of doing it manually. My experience so 
far has been.. let's say not encouraging.  For starters I had issues 
compiling my interop library. My project.clj looks  like this:

(defprojectde.janthomae/leiningenplugin  "1.1.0-SNAPSHOT"
   :description  "IntelliJ plugin for controlling Leiningen"
   :dependencies  [[org.clojure/clojure  "1.4.0"]
                   [leiningen-core  "2.0.0-SNAPSHOT"]]
   :plugins  [[lein-pprint  "1.1.1"]]
   :dev-dependencies  [[junit/junit  "4.8.2"]]
   :source-paths  ["src"]
   :resource-paths  ["lein-resources"]
   :compile-path  "classes"
   :aot  :all
;  :disable-implicit-clean true
   :omit-source  true
   :target-dir  "out"
   :jar-name  "leiningen-interop.jar")


Whenever I added something like

(use 'leiningen.core.project)

to a piece of code I was getting a: java.lang.ClassNotFoundException: 
clojure.lang.ILookupHost when doing a lein compile or lein.jar. After I 
added a :eval-in :leiningen  to the project.cljthat exception went away. 
I'd be grateful if someone could explain this to me, as I'm by far no 
clojure god.

-----

With that in place, I could at least compile my leiningen-interop.jar so 
I could access Leiningen from Java. The leiningen-interop.jar contains a 
single class:

(ns de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile
   (:require [leiningen.core.project :as p]
             [leiningen.core.classpath :as cp]   )
   (:import [java.io File])
   (:gen-class
     :init init
     :methods [[getName [] String]
               [getNamespace [] String]
               [getVersion [] String]
               [getSourcePath [] String]
               [getTestPath [] String]
               [getResourcesPath [] String]
               [getCompilePath [] String]
               [getLibraryPath [] String]
               [getTargetDir [] String]
               [getProjectFile [] String]
               [getClassPath [] "[Ljava.lang.String;"]
               [isValid [] Boolean]
               [getError [] Throwable]]
     :constructors {[String] []}
     :state state)
   )


;; Internal functions
(defn project [this]
   (:project @(.state this)))

(defn status [this]
   (:status @(.state this)))

(defn exception [this]
   (:exception @(.state this)))

(defn project-path [this]
   (:path @(.state this)))

(defn get-classpath [project]
   (cp/get-classpath project))

(defn read-project
   "Reads the leiningen project file. Returns a hash with a :status 
keyword. If loading the file succeeded
   :status is true and the hash contains an additional :project keyword 
holding the leiningen project. Otherwise
   :status is false and the hash contains an addtional :exception 
keyword holding the exception that occured."
   [file]
   (binding [*ns* (the-ns 
'de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile)]
     (try
       {:status true :project (p/read file)}
       (catch Exception e
         {:status false :exception e}))))

;; Class interface

(defn -init [file]
   (let [p (read-project file)]
     [[] (atom (assoc p :path file))]))

(defn -isValid [this]
   (status this))

(defn -getError [this]
   (exception this))

(defn -getName [this]
   (if-let [project-name (:name (project this))]
     (name project-name)
     "<undefined>"))

(defn -getNamespace [this]
   (if-let [project-name (:name (project this))]
     (namespace (:name (project this)))
     nil))

(defn -getVersion [this]
   (if-let [project-version (:version (project this))]
     project-version
     "<undefined>"))

(defn -getSourcePath [this]
   (:source-path (project this) "src"))

(defn -getTestPath [this]
   (:test-path (project this) "test"))

(defn -getResourcesPath [this]
   (:resources-path (project this) "resources"))

(defn -getCompilePath [this]
   (:compile-path (project this) "classes"))

(defn -getLibraryPath [this]
   (:library-path (project this) "lib"))

(defn -getTargetDir [this]
   (let [p (project this)]
     (:target-dir p (:jar-dir p ""))))

(defn -getProjectFile [this]
   (project-path this))

(defn -getClassPath [this]
   (get-classpath (project this)))



I got a classloader which has the leiningen-standalone.jar, 
clojure-1.4.0.jar and my leiningen-interop.jar in it's classpath. Now 
whenever I'm trying to initialize the LeiningenProjectFile class, I get 
this error:

java.io.FileNotFoundException: Could not locate 
leiningen/core/project__init.class or leiningen/core/project.clj on 
classpath:
     at clojure.lang.RT.load(RT.java:432)
     at clojure.lang.RT.load(RT.java:400)
     at clojure.core$load$fn__4890.invoke(core.clj:5415)
     at clojure.core$load.doInvoke(core.clj:5414)
     at clojure.lang.RestFn.invoke(RestFn.java:408)
     at clojure.core$load_one.invoke(core.clj:5227)
     at clojure.core$load_lib.doInvoke(core.clj:5264)
     at clojure.lang.RestFn.applyTo(RestFn.java:142)
     at clojure.core$apply.invoke(core.clj:603)
     at clojure.core$load_libs.doInvoke(core.clj:5298)
     at clojure.lang.RestFn.applyTo(RestFn.java:137)
     at clojure.core$apply.invoke(core.clj:603)
     at clojure.core$require.doInvoke(core.clj:5381)
     at clojure.lang.RestFn.invoke(RestFn.java:421)
     at 

de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile$loading__4784__auto__.invoke(LeiningenProjectFile.clj:1)
     at 
de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile__init.load(Unknown 
Source)
     at 

de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile__init.<clinit>(Unknown

Source)
     at java.lang.Class.forName0(Native Method)
     at java.lang.Class.forName(Class.java:247)
     at clojure.lang.RT.loadClassForName(RT.java:2056)
     at clojure.lang.RT.load(RT.java:419)
     at clojure.lang.RT.load(RT.java:400)
     at clojure.core$load$fn__4890.invoke(core.clj:5415)
     at clojure.core$load.doInvoke(core.clj:5414)
     at clojure.lang.RestFn.invoke(RestFn.java:408)
     at clojure.lang.Var.invoke(Var.java:415)
     at 
de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile.<clinit>(Unknown 
Source)

I was trying to find out what classloader clojure is using to load the 
classes, so I added a few expressions to the debugger:

RT.baseLoader().getURLS()
- 
file:/Users/kork/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar

So Clojure's base loader points to the leiningen-standalone.jar and it 
actually should be able to resolve the leiningen.core.project__init class.

I tried:
RT.baseLoader().getResource("leiningen/core/project__init.class")
  
jar:file:/Users/kork/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar!/leiningen/core/project__init.class

So the class-file can be resolved.

Next debugger expression:
Class.forName("leiningen.core.project__init",false, RT.baseLoader())
   {java.lang.Class@10291} class leiningen.core.project__init

So the class can also be resolved via Class.forName().

Yet I still get the above exception. I'm probably missing something 
simple here, but I already spent a few evenings on this without any 
progress. So maybe a Leiningen/Clojure guru can help me out here.

Thank you very much.

Kind regards,
Jan

Re: [leiningen] Issues getting leiningen-core to work with Java interop

From:
Laurent Petit
Date:
2012-08-23 @ 19:57
Hi,

Maybe you could look at how I did it in counterclockwise ?

I cannot produce much info right now, but depending on your interest, I can
spend time with you next
Thursday.

Cheers,
Laurent

Sent from a smartphone, please excuse the brevity/typos.

Le 23 août 2012 à 21:47, "Jan Thomä" <janthomae@janthomae.de> a écrit :

 Hi,

I'm the maintainer of the Leiningen Plugin for IntelliJ and I'm currently
trying to use leiningen-core to parse the project files and resolve the
dependencies instead of doing it manually. My experience so far has been..
let's say not encouraging.  For starters I had issues compiling my interop
library. My project.clj looks  like this:

(defproject de.janthomae/leiningenplugin "1.1.0-SNAPSHOT"
  :description "IntelliJ plugin for controlling Leiningen"
  :dependencies [[org.clojure/clojure "1.4.0"]
                  [leiningen-core "2.0.0-SNAPSHOT"]]
  :plugins [[lein-pprint "1.1.1"]]
  :dev-dependencies [[junit/junit "4.8.2"]]
  :source-paths ["src"]
  :resource-paths ["lein-resources"]
  :compile-path "classes"
  :aot :all;  :disable-implicit-clean true
  :omit-source true
  :target-dir "out"
  :jar-name "leiningen-interop.jar")


Whenever I added something like

(use 'leiningen.core.project)

to a piece of code I was getting  a: java.lang.ClassNotFoundException:
clojure.lang.ILookupHost when doing a lein compile or lein.jar. After I
added a  :eval-in :leiningen   to the project.clj that exception went away.
I'd be grateful if someone could explain this to me, as I'm by far no
clojure god.

-----

With that in place, I could at least compile my leiningen-interop.jar so I
could access Leiningen from Java. The leiningen-interop.jar contains a
single class:

(ns de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile
  (:require [leiningen.core.project :as p]
            [leiningen.core.classpath :as cp]   )
  (:import [java.io File])
  (:gen-class
    :init init
    :methods [[getName [] String]
              [getNamespace [] String]
              [getVersion [] String]
              [getSourcePath [] String]
              [getTestPath [] String]
              [getResourcesPath [] String]
              [getCompilePath [] String]
              [getLibraryPath [] String]
              [getTargetDir [] String]
              [getProjectFile [] String]
              [getClassPath [] "[Ljava.lang.String;"]
              [isValid [] Boolean]
              [getError [] Throwable]]
    :constructors {[String] []}
    :state state)
  )


;; Internal functions
(defn project [this]
  (:project @(.state this)))

(defn status [this]
  (:status @(.state this)))

(defn exception [this]
  (:exception @(.state this)))

(defn project-path [this]
  (:path @(.state this)))

(defn get-classpath [project]
  (cp/get-classpath project))

(defn read-project
  "Reads the leiningen project file. Returns a hash with a :status keyword.
If loading the file succeeded
  :status is true and the hash contains an additional :project keyword
holding the leiningen project. Otherwise
  :status is false and the hash contains an addtional :exception keyword
holding the exception that occured."
  [file]
  (binding [*ns* (the-ns
'de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile)]
    (try
      {:status true :project (p/read file)}
      (catch Exception e
        {:status false :exception e}))))

;; Class interface

(defn -init [file]
  (let [p (read-project file)]
    [[] (atom (assoc p :path file))]))

(defn -isValid [this]
  (status this))

(defn -getError [this]
  (exception this))

(defn -getName [this]
  (if-let [project-name (:name (project this))]
    (name project-name)
    "<undefined>"))

(defn -getNamespace [this]
  (if-let [project-name (:name (project this))]
    (namespace (:name (project this)))
    nil))

(defn -getVersion [this]
  (if-let [project-version (:version (project this))]
    project-version
    "<undefined>"))

(defn -getSourcePath [this]
  (:source-path (project this) "src"))

(defn -getTestPath [this]
  (:test-path (project this) "test"))

(defn -getResourcesPath [this]
  (:resources-path (project this) "resources"))

(defn -getCompilePath [this]
  (:compile-path (project this) "classes"))

(defn -getLibraryPath [this]
  (:library-path (project this) "lib"))

(defn -getTargetDir [this]
  (let [p (project this)]
    (:target-dir p (:jar-dir p ""))))

(defn -getProjectFile [this]
  (project-path this))

(defn -getClassPath [this]
  (get-classpath (project this)))



I got a classloader which has the leiningen-standalone.jar,
clojure-1.4.0.jar and my leiningen-interop.jar in it's classpath. Now
whenever I'm trying to initialize the LeiningenProjectFile class, I get
this error:

java.io.FileNotFoundException: Could not locate
leiningen/core/project__init.class or leiningen/core/project.clj on
classpath:
    at clojure.lang.RT.load(RT.java:432)
    at clojure.lang.RT.load(RT.java:400)
    at clojure.core$load$fn__4890.invoke(core.clj:5415)
    at clojure.core$load.doInvoke(core.clj:5414)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invoke(core.clj:5227)
    at clojure.core$load_lib.doInvoke(core.clj:5264)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invoke(core.clj:603)
    at clojure.core$load_libs.doInvoke(core.clj:5298)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invoke(core.clj:603)
    at clojure.core$require.doInvoke(core.clj:5381)
    at clojure.lang.RestFn.invoke(RestFn.java:421)
    at

de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile$loading__4784__auto__.invoke(LeiningenProjectFile.clj:1)
    at
de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile__init.load(Unknown
Source)
    at
de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile__init.<clinit>(Unknown
Source)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:247)
    at clojure.lang.RT.loadClassForName(RT.java:2056)
    at clojure.lang.RT.load(RT.java:419)
    at clojure.lang.RT.load(RT.java:400)
    at clojure.core$load$fn__4890.invoke(core.clj:5415)
    at clojure.core$load.doInvoke(core.clj:5414)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:415)
    at
de.janthomae.leiningenplugin.leiningen.LeiningenProjectFile.<clinit>(Unknown
Source)

I was trying to find out what classloader clojure is using to load the
classes, so I added a few expressions to the debugger:

RT.baseLoader().getURLS()
-
file:/Users/kork/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar

So Clojure's base loader points to the leiningen-standalone.jar and it
actually should be able to resolve the leiningen.core.project__init class.

I tried:
RT.baseLoader().getResource("leiningen/core/project__init.class")


jar:file:/Users/kork/.lein/self-installs/leiningen-2.0.0-preview7-standalone.jar!/leiningen/core/project__init.class

So the class-file can be resolved.

Next debugger expression:
Class.forName("leiningen.core.project__init",false, RT.baseLoader())
  {java.lang.Class@10291} class leiningen.core.project__init

So the class can also be resolved via Class.forName().

Yet I still get the above exception. I'm probably missing something simple
here, but I already spent a few evenings on this without any progress. So
maybe a Leiningen/Clojure guru can help me out here.

Thank you very much.

Kind regards,
Jan

Re: [leiningen] Issues getting leiningen-core to work with Java interop

From:
Jan Thomä
Date:
2012-08-24 @ 06:35
could not decode message