2017-08-04 98 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

謝謝,這是一個很好的起點。我實際上對軟件有控制權,但是團隊的前成員寫了這個軟件,我現在無法訪問他。 –