2017-08-04 89 views
1

我相对Clojure和Java的新手。我有一个现有的Clojure项目,别人写道,我试图使用node-java嵌入到NodeJS中。如何从Clojure中导出Java类(.jar)?

Clojure的

该项目定义了一个命名空间提供了一定的公共职能,比如:

(ns my.namespace 
    (:require ...etc...)) 

(defn dosomething ...) 
(defn dosomethingelse ...) 

我已经建立了leiningen(lein jarlein uberjar)项目。

问题

节点-Java中的#import() docs说我需要导入一个java类,像这样:

const java = require('java'); 
var Test = java.import('Test'); 
  1. 我怎样才能访问这些功能(这应该是Java类的静态方法?)
  2. 我接近这一切都错了吗? =)

更新

感谢MAGOS(以下回答)我做了一点进展。事实证明,我可以在(ns ...)范围内使用(:gen-class :name my.name)来告诉它生成一个类。如果我添加一个配置文件到project.clj像这样:

... 
:profiles { 
    ... 
    :uberjar {:aot :all} 
} 
... 

它会编译,我现在可以看到类中的节点。不过,我仍然没有想出如何导出这些方法。现在就在那部分工作。

+0

我认为导入由Java项目制作的.jar和由Clojure项目制作的.jar是没有区别的。您是否能够从Java项目导入任何.jars文件? Clojure因素可能是红鲱鱼。 – Carcigenicate

+0

@Carcigenicate当我添加jar时,它没有给出错误。但更重要的一点(我认为)是我不知道生成的.jar中的类是什么。我能否以某种方式查明罐子中的哪些类可用? –

+0

那,我不知道。我会在一个好的IDE中打开它,尝试导入它,然后看看自动完成是否给你提示。我希望他们都在'Test'下,并使用JS的成员访问运算符进行访问。如果你找不到深入的指南,只是玩耍可能会有用。 – Carcigenicate

回答

0

注意:我是通过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方法。

  1. 通过在-前加上相同的签名来创建该方法的暴露版本。它应该简单地调用你想要公开的函数。

    (defn -excite [mystr] (excite mystr)) 
    
  2. 申报要生成一个类和导出方法(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] 
        ])) 
    

    注意,你可以有选择地删除#^{:static true},如果你不希望提供这作为一个静态方法。

  3. 在你project.clj(假设你使用leiningen),加入名列前茅的时间汇编指令到您的:profiles项:

    :profiles {:uberjar {:aot :all}} 
    
  4. 编译您uberjar:

    lein uberjar 
    

生成的.jar文件将有一个my.classname类与静态方法excite

3

因为别人写了Clojure,我会假设你没有控制它。推荐使用来自其他JVM语言的Clojure代码的方法是从类clojure.java.api.Clojure引导。这个类允许你从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

+0

谢谢,这是一个很好的起点。我实际上对软件有控制权,但是团队的前成员写了这个软件,我现在无法访问他。 –