从java调用clojure [英] Calling clojure from java

查看:176
本文介绍了从java调用clojure的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从java调用clojure的大多数热门google命中已过时,并建议使用 clojure.lang.RT 编译源代码。如果你已经从Clojure项目中构建了一个jar并将其包含在类路径中,你能否帮助我们清楚地说明如何从Java调用Clojure?

解决方案

更新:自发布此答案后,可用的某些工具已更改。在原始答案之后,有一个更新,包括如何使用当前工具构建示例的信息。



这不像编译到jar和调用内部方法。似乎有一些技巧,使它所有的工作,但。这里有一个简单的Clojure文件,可以编译为jar:

 (ns com.domain.tiny 
(:gen-class
:name com.domain.tiny
:methods [#^ {:static true} [binomial [int int] double]]))

(defn binomial
计算二项式系数
[nk]
(let [a(inc n)]
(loop [b 1
c 1] b $ b(if(> bk)
c
(recur(inc b)(*(/( - ab)b)c))))))


[nk]
(binomial nk))

(defn -main [ ]
(println(str(binomial 5 3):(binomial 5 3)))
(println(str(binister 10042 111):(binomial 10042 111)))

如果你运行它,你应该会看到:

 (二项式5 3):10 
(二项式10042 111):49068389575068144946633777 ...
pre>

下面是一个Java程序,它调用 tiny中的 -binomial jar

  import com.domain.tiny; 

public class Main {

public static void main(String [] args){
System.out.println((binomial 5 3): tiny.binomial(5,3));
System.out.println((binister 10042,111):+ tiny.binomial(10042,111));
}
}

输出为:

 (二项式5 3):10.0 
(二项式10042,111):4.9068389575068143E263
pre>

第一个魔术是使用中的:methods class 语句。这似乎需要让你访问Clojure函数像Java中的静态方法。



第二件事是创建一个可以被Java调用的包装函数。注意, -binomial 的第二个版本在它前面有一个破折号。



当然,Clojure jar本身必须在类路径上。此示例使用Clojure-1.1.0 jar。



更新:此回答已使用以下工具重新测试:




  • Clojure 1.5.1

  • Leiningen 2.1.3

  • JDK 1.7.0更新25



Clojure部分



首先使用Leiningen创建一个项目和关联的目录结构:

  C:\projects> lein new com.domain。 tiny 

现在,切换到项目目录。

  C:\projects> cd com.domain.tiny 

在项目目录中,打开 project.clj 文件并对其进行编辑,内容如下所示。

 (defproject com.domain.tiny0.1.0-SNAPSHOT
:description一个独立的例子Clojure-Java interop
:url http://clarkonium.net/2013/06/java-clojure-interop-an-update/
:license {:nameEclipse公共许可证
:urlhttp:// www .eclipse.org / legal / epl-v10.html}
:dependencies [[org.clojure / clojure1.5.1]]
:aot:all
:main com。 domain.tiny)



现在,确保所有的依赖项(Clojure)可用。

  C:\projects\com.domain.tiny> lein deps 

您可能会在此时看到有关下载Clojure jar的消息。



现在编辑Clojure文件 C:\projects\com.domain.tiny\src\com\domain\tiny.clj ,使其包含原始答案中显示的Clojure程序。 (此文件是在Leiningen创建项目时创建的)



这里的大部分魔术都在命名空间声明中。 :gen-class 告诉系统使用单个静态方法创建一个名为 com.domain.tiny 的类 binomial ,一个函数接受两个整数参数并返回一个double。有两个类似命名的函数 binomial ,一个传统的Clojure函数和 -binomial 和可从Java访问的包装。请注意函数名 -binomial 中的连字符。默认前缀是连字符,但如果需要,它可以更改为其他值。 -main 函数只是对二项函数进行几次调用,以确保我们获得正确的结果。要这样做,编译类并运行程序。

  C:\projects\com.domain.tiny> lein运行

您应该看到原始答案中显示的输出。



现在把它包装在一个罐子里,放在一个方便的地方。

  C:\projects\com.domain.tiny> lein jar 
创建的C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny> mkdir \\ \\ target \lib

C:\projects\com.domain.tiny> copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
复制1个文件。

C:\projects\com.domain.tiny> copyC:< clojure jar的路径> \clojure-1.5.1.jartarget\lib \
复制了1个文件。

Java零件



Leiningen有一个内置的任务, lein-javac ,应该能够帮助Java编译。不幸的是,它似乎在2.1.3版本中被打破。它找不到已安装的JDK,它找不到Maven存储库。两者的路径都在我的系统上嵌入了空格。我假设这是问题。任何Java IDE都可以处理编译和打包。



首先创建文件 Main.java

编译java部分

javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java

现在创建一个包含一些元信息的文件,以添加到我们要构建的jar中。在 Manifest.txt 中,添加以下文本

  lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar 
Main-Class:Main

现在将其打包成一个大的jar文件,包括我们的Clojure程序和Clojure jar。

  C:\projects\com.domain.tiny\target> jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT。 jar lib\clojure-1.5.1.jar 

运行程序:

  C:\projects\com.domain.tiny\target> java -jar Interop.jar 
(二项式5 3) :10.0
(二项式10042,111):4.9068389575068143E263

输出基本上与



如上所述,Java IDE可能会处理乱码的编译参数和包装。


Most of the top google hits for "calling clojure from java" are outdated and recommend using clojure.lang.RT to compile the source code. Could you help with a clear explanation of how to call Clojure from Java assuming you have already built a jar from the Clojure project and included it in the classpath?

解决方案

Update: Since this answer was posted, some of the tools available have changed. After the original answer, there is an update including information on how to build the example with current tools.

It isn't quite as simple as compiling to a jar and calling the internal methods. There do seem to be a few tricks to make it all work though. Here's an example of a simple Clojure file that can be compiled to a jar:

(ns com.domain.tiny
  (:gen-class
    :name com.domain.tiny
    :methods [#^{:static true} [binomial [int int] double]]))

(defn binomial
  "Calculate the binomial coefficient."
  [n k]
  (let [a (inc n)]
    (loop [b 1
           c 1]
      (if (> b k)
        c
        (recur (inc b) (* (/ (- a b) b) c))))))

(defn -binomial
  "A Java-callable wrapper around the 'binomial' function."
  [n k]
  (binomial n k))

(defn -main []
  (println (str "(binomial 5 3): " (binomial 5 3)))
  (println (str "(binomial 10042 111): " (binomial 10042 111)))
)

If you run it, you should see something like:

(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...

And here's a Java program that calls the -binomial function in the tiny.jar.

import com.domain.tiny;

public class Main {

    public static void main(String[] args) {
        System.out.println("(binomial 5 3): " + tiny.binomial(5, 3));
        System.out.println("(binomial 10042, 111): " + tiny.binomial(10042, 111));
    }
}

It's output is:

(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

The first piece of magic is using the :methods keyword in the gen-class statement. That seems to be required to let you access the Clojure function something like static methods in Java.

The second thing is to create a wrapper function that can be called by Java. Notice that the second version of -binomial has a dash in front of it.

And of course the Clojure jar itself must be on the class path. This example used the Clojure-1.1.0 jar.

Update: This answer has been re-tested using the following tools:

  • Clojure 1.5.1
  • Leiningen 2.1.3
  • JDK 1.7.0 Update 25

The Clojure Part

First create a project and associated directory structure using Leiningen:

C:\projects>lein new com.domain.tiny

Now, change to the project directory.

C:\projects>cd com.domain.tiny

In the project directory, open the project.clj file and edit it such that the contents are as shown below.

(defproject com.domain.tiny "0.1.0-SNAPSHOT"
  :description "An example of stand alone Clojure-Java interop"
  :url "http://clarkonium.net/2013/06/java-clojure-interop-an-update/"
  :license {:name "Eclipse Public License"
  :url "http://www.eclipse.org/legal/epl-v10.html"}
  :dependencies [[org.clojure/clojure "1.5.1"]]
  :aot :all
  :main com.domain.tiny)

Now, make sure all of the dependencies (Clojure) are available.

C:\projects\com.domain.tiny>lein deps

You may see a message about downloading the Clojure jar at this point.

Now edit the Clojure file C:\projects\com.domain.tiny\src\com\domain\tiny.clj such that it contains the Clojure program shown in the original answer. (This file was created when Leiningen created the project.)

Much of the magic here is in the namespace declaration. The :gen-class tells the system to create a class named com.domain.tiny with a single static method called binomial, a function taking two integer arguments and returning a double. There are two similarly named functions binomial, a traditional Clojure function, and -binomial and wrapper accessible from Java. Note the hyphen in the function name -binomial. The default prefix is a hyphen, but it can be changed to something else if desired. The -main function just makes a couple of calls to the binomial function to assure that we are getting the correct results. To do that, compile the class and run the program.

C:\projects\com.domain.tiny>lein run

You should see output shown in the original answer.

Now package it up in a jar and put it someplace convenient. Copy the Clojure jar there too.

C:\projects\com.domain.tiny>lein jar
Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar
C:\projects\com.domain.tiny>mkdir \target\lib

C:\projects\com.domain.tiny>copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\
        1 file(s) copied.

C:\projects\com.domain.tiny>copy "C:<path to clojure jar>\clojure-1.5.1.jar" target\lib\
        1 file(s) copied.

The Java Part

Leiningen has a built-in task, lein-javac, that should be able to help with the Java compilation. Unfortunately, it seems to be broken in version 2.1.3. It can't find the installed JDK and it can't find the Maven repository. The paths to both have embedded spaces on my system. I assume that is the problem. Any Java IDE could handle the compilation and packaging too. But for this post, we're going old school and doing it at the command line.

First create the file Main.java with the contents shown in the original answer.

To compile java part

javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java

Now create a file with some meta-information to add to the jar we want to build. In Manifest.txt, add the following text

Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main

Now package it all up into one big jar file, including our Clojure program and the Clojure jar.

C:\projects\com.domain.tiny\target>jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar

To run the program:

C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

The output is essentially identical to that produced by Clojure alone, but the result has been converted to a Java double.

As mentioned, a Java IDE will probably take care of the messy compilation arguments and the packaging.

这篇关于从java调用clojure的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆