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

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

问题描述

大多数关于从 Java 调用 clojure"的谷歌热门搜索已经过时,建议使用 clojure.lang.RT 来编译源代码.假设您已经从 Clojure 项目构建了一个 jar 并将其包含在类路径中,您能否帮助清楚地解释如何从 Java 调用 Clojure?

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.

它不像编译成 jar 并调用内部方法那么简单.不过,似乎确实有一些技巧可以使其全部工作.下面是一个可以编译为 jar 的简单 Clojure 文件示例:

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...

这是一个调用 tiny.jar 中的 -binomial 函数的 Java 程序.

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));
    }
}

它的输出是:

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

第一个魔法是在 gen-class 语句中使用 :methods 关键字.这似乎是让您访问 Clojure 函数(类似于 Java 中的静态方法)所必需的.

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.

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

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.

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

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
  • 莱宁根 2.1.3
  • JDK 1.7.0 更新 25

Clojure 部分

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

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

在项目目录下,打开project.clj文件,编辑内容如下图.

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)

现在,确保所有依赖项 (Clojure) 都可用.

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

C:projectscom.domain.tiny>lein deps

此时您可能会看到一条关于下载 Clojure jar 的消息.

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

现在编辑 Clojure 文件 C:projectscom.domain.tinysrccomdomain iny.clj 使其包含原始答案中显示的 Clojure 程序.(这个文件是在 Leiningen 创建项目时创建的.)

Now edit the Clojure file C:projectscom.domain.tinysrccomdomain iny.clj such that it contains the Clojure program shown in the original answer. (This file was created when Leiningen created the project.)

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

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:projectscom.domain.tiny>lein run

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

You should see output shown in the original answer.

现在把它装在一个罐子里,放在方便的地方.也将 Clojure jar 复制到那里.

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

C:projectscom.domain.tiny>lein jar
Created C:projectscom.domain.tiny	argetcom.domain.tiny-0.1.0-SNAPSHOT.jar
C:projectscom.domain.tiny>mkdir 	argetlib

C:projectscom.domain.tiny>copy targetcom.domain.tiny-0.1.0-SNAPSHOT.jar targetlib
        1 file(s) copied.

C:projectscom.domain.tiny>copy "C:<path to clojure jar>clojure-1.5.1.jar" targetlib
        1 file(s) copied.

Java 部分

Leiningen 有一个内置任务,lein-javac,应该能够帮助进行 Java 编译.不幸的是,它似乎在 2.1.3 版本中被破坏了.它找不到已安装的 JDK,也找不到 Maven 存储库.两者的路径都在我的系统上嵌入了空格.我认为这就是问题所在.任何 Java IDE 也可以处理编译和打包.但是对于这篇博文,我们将采用传统方法并在命令行中进行操作.

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.

首先使用原始答案中显示的内容创建文件 Main.java.

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

编译java部分

javac -g -cp targetcom.domain.tiny-0.1.0-SNAPSHOT.jar -d targetsrccomdomainMain.java

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

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: libcom.domain.tiny-0.1.0-SNAPSHOT.jar libclojure-1.5.1.jar
Main-Class: Main

现在将它们全部打包成一个大的 jar 文件,包括我们的 Clojure 程序和 Clojure jar.

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

C:projectscom.domain.tiny	arget>jar cfm Interop.jar Manifest.txt Main.class libcom.domain.tiny-0.1.0-SNAPSHOT.jar libclojure-1.5.1.jar

运行程序:

C:projectscom.domain.tiny	arget>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263

输出与单独由 Clojure 生成的输出基本相同,但结果已转换为 Java 双精度值.

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

如前所述,Java IDE 可能会处理杂乱的编译参数和打包.

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

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

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