-1

I am trying to call some Clojure code from Java, but I get this error when trying to "require" the file:

Could not locate proj/core__init.class, proj/core.clj or proj/core.cljc on classpath.
    at clojure.lang.RT.load(RT.java:462)
    at clojure.lang.RT.load(RT.java:424)
    at clojure.core$load$fn__6839.invoke(core.clj:6126)
    at clojure.core$load.invokeStatic(core.clj:6125)
    at clojure.core$load.doInvoke(core.clj:6109)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.core$load_one.invokeStatic(core.clj:5908)
    at clojure.core$load_one.invoke(core.clj:5903)
    at clojure.core$load_lib$fn__6780.invoke(core.clj:5948)
    at clojure.core$load_lib.invokeStatic(core.clj:5947)
    at clojure.core$load_lib.doInvoke(core.clj:5928)
    at clojure.lang.RestFn.applyTo(RestFn.java:142)
    at clojure.core$apply.invokeStatic(core.clj:667)
    at clojure.core$load_libs.invokeStatic(core.clj:5985)
    at clojure.core$load_libs.doInvoke(core.clj:5969)
    at clojure.lang.RestFn.applyTo(RestFn.java:137)
    at clojure.core$apply.invokeStatic(core.clj:667)
    at clojure.core$require.invokeStatic(core.clj:6007)
    at clojure.core$require.doInvoke(core.clj:6007)
    at clojure.lang.RestFn.invoke(RestFn.java:408)
    at clojure.lang.Var.invoke(Var.java:384)
    at proj.Main.main 

The Clojure code is as follows:

(ns proj.core)

(defn foo
  "I don't do a whole lot."
  [x]
  (println x "Hello, World!"))

and the java code:

package proj;

import clojure.java.api.Clojure;
import clojure.lang.IFn;

public class Main {
    public static void main(String[] args) {
        IFn require = Clojure.var("clojure.core", "require");
        require.invoke(Clojure.read("proj.core"));
    }
}

I've tried following this guide, for calling clojure code from java when the files are in the same project: https://push-language.hampshire.edu/t/calling-clojure-code-from-java/865

I've also seen this post, but it didn't help with my issue: Calling clojure from java

EDIT: Both files are in the same package

EDIT: The file system layout is as follows

D:.
│   first_try.iml
│   project.clj
│
├───src
│   └───proj
│           core.clj
│           Main.java
│
└───target
    └───classes
        └───proj
                Main.class

Also, I am using the default IntelliJ Application configuration to run the app, and I have a Leiningen configuration as well for testing the Clojure functions directly from REPL

Ghosty Frosty
  • 159
  • 2
  • 12
  • Could you please provide the exact file system layout? E.g. use `find -type f` and maybe trim the result to the relevant things. Also add what build-tool you are using and how you run this. Some build tools might just ignore .clj files in a java-src tree instead treading them like resource files. – cfrick May 08 '21 at 10:43
  • @cfrick I edited the question to include the file system layout and also the build tools. I don't know what the default build tool IntelliJ is using on Windows is, but I hope it's enough. – Ghosty Frosty May 08 '21 at 10:57

1 Answers1

1

Here is a full minimal working version showing Clojure called from Java.

Project layout:

.
├── project.clj
├── resources
└── src
    ├── clojure
    │   └── proj
    │       └── core.clj
    └── java
        └── proj
            └── Main.java

project.clj:

(defproject overflow-java "0.1.0-SNAPSHOT"
  :source-paths ["src/clojure"]
  :java-source-paths ["src/java"]
  :dependencies [[org.clojure/clojure "1.10.1"]]
  :repl-options {:init-ns proj.core})

src/clojure/proj/core.clj:

(ns proj.core)

(defn foo
  "I don't do a whole lot."
  [x]
  (println x "Hello, World!"))

src/java/proj/Main.java:

package proj;

import clojure.java.api.Clojure;
import clojure.lang.IFn;

public class Main {
    public static void main(String[] args) {
        IFn require = Clojure.var("clojure.core", "require");
        require.invoke(Clojure.read("proj.core"));
        IFn foo = Clojure.var("proj.core", "foo");
        foo.invoke("Steffan");
    }
}

Build uberjar and run:

$ lein uberjar
$ java -cp target/overflow-java-0.1.0-SNAPSHOT-standalone.jar proj.Main

Run output:

Steffan Hello, World!

The Leiningen docs advise putting Java and Clojure source files in their own source roots.

If you wish to run the project directly In IntelliJ you will need to configure the project module in Project Settings > Project Structure > Modules. In the "Sources" tab, select the entry src/clojure (it will be coloured blue as a "Source Folder") then click the button "Resources" to mark it as a resources root instead. This ensures the .clj files are present on the classpath when running the Java application in IntelliJ. You can now run the application by clicking on the green arrow in the gutter by Java method main in class proj.Main. You'll need to reapply this module change each time Cursive refreshes the Leiningen project, as the change does not stick.

Steffan Westcott
  • 2,121
  • 1
  • 3
  • 13
  • This is priceless and works like a charm. I tried adding the normal jar (created from lein jar) to the project dependencies but that didn't seem to work, but the uberjar works perfectly. I don't really understand why that is the case but I'm glad it works. – Ghosty Frosty May 08 '21 at 15:24
  • 1
    `lein uberjar` includes the dependencies (plus all their transitive dependencies) to make a "standalone" JAR. In this minimal case, those dependencies are Clojure itself (plus its dependencies). – Steffan Westcott May 08 '21 at 15:32