如何从 Clojure 导出 Java class (.jar)?
How can I export a Java class (.jar) from Clojure?
我是 Clojure 和 Java 的新手。我有一个其他人写的现有 Clojure 项目,我正在尝试使用 node-java 嵌入到 NodeJS 中。
Clojure
该项目定义了一个提供某些public功能的命名空间,例如:
(ns my.namespace
(:require ...etc...))
(defn dosomething ...)
(defn dosomethingelse ...)
我已经使用 leiningen(lein jar
和 lein uberjar
)构建了项目。
问题
node-java 上的 #import() docs 说我需要像这样导入 java class:
const java = require('java');
var Test = java.import('Test');
- 如何访问这些函数(大概是 Java class 静态方法?)
- 我是不是完全错了? =)
更新
感谢 Magos(下面的回答),我取得了更多进步。事实证明,我可以在 (ns ...)
范围内使用 (:gen-class :name my.name)
来告诉它生成一个 class。如果我像这样向 project.clj 添加配置文件:
...
:profiles {
...
:uberjar {:aot :all}
}
...
它将编译,我现在可以在 Node.js 中看到 class。不过,我仍然没有弄清楚如何导出这些方法。现在正在处理该部分。
由于其他人编写了 Clojure,我假设您无法控制它。使用来自其他 JVM 语言的 Clojure 代码的推荐方法是从 class clojure.java.api.Clojure
引导。 class 允许您解析 Clojure 中的 Vars,通过解析和调用其他核心 Clojure 函数,您可以加载自己的代码。根据您的示例,它可能看起来像这样:
const java = require('java');
var clojure = java.import('clojure.java.api.Clojure');
IFn require = clojure.var("clojure.core", "require");
require.invoke(clojure.read("my.namespace"));
IFn doSomething = clojure.var("my.namespace","dosomething");
//doSomething.invoke(....
如果您确实控制了 Clojure,:gen-class
allows you to export functions as methods of the namespace's generated class。
注:我结合了 Magos 的回答和 clartaq 对问题的评论得出了这个结论。
这里有简单的操作说明。假设您有这个(简单的)clojure 代码:
(ns my.namespace
"a trivial library"
(:require [something.else :as other]))
(defn excite
"make things more exciting"
[mystr]
(print-str mystr "!"))
使用这些步骤公开 excite
方法。
通过在方法前加上 -
前缀,创建具有相同签名的方法的公开版本。它应该简单地调用您希望公开的函数。
(defn -excite [mystr] (excite mystr))
在(ns ...)
中声明您要生成class和导出方法。
(ns my.namespace
"a trivial library"
(:require [something.else :as other])
(:gen-class
:name my.classname
:methods [
; metadata mtd.name signature returns
#^{:static true} [excite [String] void]
]))
请注意,如果您不想将此作为静态方法提供,您可以选择删除 #^{:static true}
。
在您的 project.clj 中(假设您使用的是 leiningen),将提前编译指令添加到您的 :profiles
条目中:
:profiles {:uberjar {:aot :all}}
编译您的 uberjar:
lein uberjar
生成的 .jar
文件将有一个 class my.classname
和静态方法 excite
.
我是 Clojure 和 Java 的新手。我有一个其他人写的现有 Clojure 项目,我正在尝试使用 node-java 嵌入到 NodeJS 中。
Clojure
该项目定义了一个提供某些public功能的命名空间,例如:
(ns my.namespace
(:require ...etc...))
(defn dosomething ...)
(defn dosomethingelse ...)
我已经使用 leiningen(lein jar
和 lein uberjar
)构建了项目。
问题
node-java 上的 #import() docs 说我需要像这样导入 java class:
const java = require('java');
var Test = java.import('Test');
- 如何访问这些函数(大概是 Java class 静态方法?)
- 我是不是完全错了? =)
更新
感谢 Magos(下面的回答),我取得了更多进步。事实证明,我可以在 (ns ...)
范围内使用 (:gen-class :name my.name)
来告诉它生成一个 class。如果我像这样向 project.clj 添加配置文件:
...
:profiles {
...
:uberjar {:aot :all}
}
...
它将编译,我现在可以在 Node.js 中看到 class。不过,我仍然没有弄清楚如何导出这些方法。现在正在处理该部分。
由于其他人编写了 Clojure,我假设您无法控制它。使用来自其他 JVM 语言的 Clojure 代码的推荐方法是从 class clojure.java.api.Clojure
引导。 class 允许您解析 Clojure 中的 Vars,通过解析和调用其他核心 Clojure 函数,您可以加载自己的代码。根据您的示例,它可能看起来像这样:
const java = require('java');
var clojure = java.import('clojure.java.api.Clojure');
IFn require = clojure.var("clojure.core", "require");
require.invoke(clojure.read("my.namespace"));
IFn doSomething = clojure.var("my.namespace","dosomething");
//doSomething.invoke(....
如果您确实控制了 Clojure,:gen-class
allows you to export functions as methods of the namespace's generated class。
注:我结合了 Magos 的回答和 clartaq 对问题的评论得出了这个结论。
这里有简单的操作说明。假设您有这个(简单的)clojure 代码:
(ns my.namespace
"a trivial library"
(:require [something.else :as other]))
(defn excite
"make things more exciting"
[mystr]
(print-str mystr "!"))
使用这些步骤公开 excite
方法。
通过在方法前加上
-
前缀,创建具有相同签名的方法的公开版本。它应该简单地调用您希望公开的函数。(defn -excite [mystr] (excite mystr))
在
(ns ...)
中声明您要生成class和导出方法。(ns my.namespace "a trivial library" (:require [something.else :as other]) (:gen-class :name my.classname :methods [ ; metadata mtd.name signature returns #^{:static true} [excite [String] void] ]))
请注意,如果您不想将此作为静态方法提供,您可以选择删除
#^{:static true}
。在您的 project.clj 中(假设您使用的是 leiningen),将提前编译指令添加到您的
:profiles
条目中::profiles {:uberjar {:aot :all}}
编译您的 uberjar:
lein uberjar
生成的 .jar
文件将有一个 class my.classname
和静态方法 excite
.