Clojure: gen-class 并在 java 中导入;包,路径,class路径

Clojure: gen-class and import it in java; packages, paths, classpaths

我想调用从 Java 编译为 class 的 Clojure 代码。

Clojure class:

(ns clj.core)

(gen-class
 :name de.wt.TestClj
 :state state
 :init init
 :prefix "-"
 :main false
 :methods [[setValue [String] void]
           [getValue [] String]])

(defn -init []
  [[] (atom {:value ""})])

(defn -setValue [this val]
  (swap! (.state this) assoc :value val))

(defn -getValue [this]
  (@(.state this) :value))

使用 lein uberjar 编译并将输出 -standalone.jar 复制到子目录 de/wt.

下的 Java 项目中

.java 文件:

import de.wt.TestClj;

class CljTest {
    public static void main(String args[]) {
        TestClj test = new TestClj();
        System.out.println("Pre: " + test.getValue());
        test.setValue("foo");
        System.out.println("Post: " + test.getValue());
    }
}

现在当我尝试编译时

~/testbed/cljava/java % tree                                                                 [1 14:44:53]
.
├── CljTest.java
├── de
│   └── wt
│       └── TestClj.jar
└── TestClj.jar

2 directories, 3 files
~/testbed/cljava/java % javac -cp ./:./de/wt/TestClj.jar CljTest.java                        

CljTest.java:1: error: package de.wt does not exist
import de.wt.TestClj;
^
CljTest.java:5: error: cannot find symbol
TestClj test = new TestClj();
^
symbol:   class TestClj
location: class CljTest
CljTest.java:5: error: cannot find symbol
TestClj test = new TestClj();
^
symbol:   class TestClj
location: class CljTest
3 errors

命名files/packages、创建目录和设置class路径需要遵循什么方案?

您应该能够在您的 jar 中看到 java class,类似于:

 $ jar tvf target/default-0.1.0-SNAPSHOT-standalone.jar | grep TestClj
 2090 Mon Jan 01 18:43:12 CET 2018 de/wt/TestClj.class

如果没有,请确保您的 project.clj 中有一个 :aot(提前编译)指令:

(defproject default "0.1.0-SNAPSHOT"
  :description "FIXME: write description"
  :url "http://example.com/FIXME"
  :license {:name "Eclipse Public License"
        :url "http://www.eclipse.org/legal/epl-v10.html"}
  :aot [clj.core]
  :dependencies [[org.clojure/clojure "1.7.0"]])

一旦您在 jar 中看到 .class 文件,在您的 classpath 中看到该 jar,您在 Java 代码中的导入应该可以正常工作。

如文档中所述 (https://clojure.org/reference/compilation):

Clojure compiles all code you load on-the-fly into JVM bytecode, but sometimes it is advantageous to compile ahead-of-time (AOT). Some reasons to use AOT compilation are:

To deliver your application without source

To speed up application startup

To generate named classes for use by Java

To create an application that does not need runtime bytecode generation and custom classloaders

另见 http://clojure-doc.org/articles/language/interop.html:

AOT

gen-class requires ahead-of-time (AOT) compilation. It means that before using the classes defined with gen-class, the Clojure compiler needs to produce .class files from gen-class definitions.