[英]How can I export a Java class (.jar) from Clojure?
I am relatively novice at Clojure and Java. 我是Clojure和Java的新手。 I have an existing Clojure project someone else wrote that I am trying to embed in NodeJS using node-java . 我有一个现有的Clojure项目,其他人写道我试图使用node-java嵌入NodeJS。
Clojure Clojure的
The project defines a namespace that provides certain public functions, like so: 该项目定义了一个提供某些公共函数的命名空间,如下所示:
(ns my.namespace
(:require ...etc...))
(defn dosomething ...)
(defn dosomethingelse ...)
I have built the project with leiningen ( lein jar
and lein uberjar
). 我用leiningen( lein jar
和lein uberjar
)建造了这个项目。
Questions 问题
The #import() docs on node-java say I need to import a java class like so: node-java上的#import()文档说我需要像这样导入一个java类:
const java = require('java');
var Test = java.import('Test');
Update 更新
Thanks to Magos (answer below) I made a little more progress. 感谢Magos(以下回答),我取得了一些进展。 It turns out I can use (:gen-class :name my.name)
in the (ns ...)
scope to tell it to generate a class. 事实证明,我可以在(ns ...)
范围内使用(:gen-class :name my.name)
来告诉它生成一个类。 If I add a profile to the project.clj like so: 如果我向project.clj添加一个配置文件,如下所示:
...
:profiles {
...
:uberjar {:aot :all}
}
...
It will compile and I can now see the class in Node. 它将编译,我现在可以看到Node中的类。 I still haven't figured out how to export the methods, though. 不过,我仍然没有想出如何导出这些方法。 Working on that part now. 现在正在努力工作。
Since someone else wrote the Clojure, I'll assume you aren't in control of it. 由于其他人写了Clojure,我会假设你无法控制它。 The recommended approach for using Clojure code from another JVM language is bootstrapping from the class clojure.java.api.Clojure
. 从另一种JVM语言使用Clojure代码的推荐方法是从类clojure.java.api.Clojure
引导。 This class allows you to resolve Vars from Clojure, and by resolving and invoking the other core Clojure functions you can load your own code. 此类允许您从Clojure解析Vars,通过解析和调用其他核心Clojure函数,您可以加载自己的代码。 Based on your example it might look something like this: 根据您的示例,它可能看起来像这样:
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(....
If you do control the Clojure, :gen-class
allows you to export functions as methods of the namespace's generated class . 如果你确实控制了Clojure,那么:gen-class
允许你将函数导出为命名空间生成的类的方法 。
Note: I arrived at this through a combination of Magos's answer and clartaq's comment to the question. 注意:我通过结合Magos的回答和clartaq对该问题的评论来达到这个目的。
Here are simple instructions for how to do it. 以下是如何操作的简单说明。 Let's assume you have this (simple) clojure code: 假设你有这个(简单的)clojure代码:
(ns my.namespace
"a trivial library"
(:require [something.else :as other]))
(defn excite
"make things more exciting"
[mystr]
(print-str mystr "!"))
Use these steps to expose the excite
method. 使用这些步骤来公开excite
方法。
Create an exposed version of the method with the same signature by prefixing it with -
. 使用相同的签名创建方法的公开版本,方法是在其前面加上-
。 It should simply call the function you wish to expose. 它应该只是调用你想要公开的函数。
(defn -excite [mystr] (excite mystr))
Declare in (ns ...)
that you want to generate a class and export methods. 在(ns ...)
中声明要生成类和导出方法。
(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] ]))
Note that you may optionally remove the #^{:static true}
if you do not wish to provide this as a static method. 请注意,如果您不希望将此作为静态方法提供,则可以选择删除#^{:static true}
。
In your project.clj (assuming you are using leiningen), add ahead-of-time compilation instructions to your :profiles
entry: 在您的project.clj中(假设您正在使用leiningen),将以前的编译说明添加到您的:profiles
条目:
:profiles {:uberjar {:aot :all}}
Compile your uberjar: 编译你的uberjar:
lein uberjar
The resulting .jar
file will have a class my.classname
with a static method excite
. 生成的.jar
文件将有一个类my.classname
其中包含静态方法excite
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.