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?
相关问题
- Delete Messages from a Topic in Apache Kafka
- Jackson Deserialization not calling deserialize on
- How to maintain order of key-value in DataFrame sa
- StackExchange API - Deserialize Date in JSON Respo
- Difference between Types.INTEGER and Types.NULL in
Other technique that works also with other languages on top of JVM is to declare an interface for functions you want to call and then use 'proxy' function to create instance that implemennts them.
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:
If you run it, you should see something like:
And here's a Java program that calls the
-binomial
function in thetiny.jar
.It's output is:
The first piece of magic is using the
:methods
keyword in thegen-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:
The Clojure Part
First create a project and associated directory structure using Leiningen:
Now, change to the project directory.
In the project directory, open the
project.clj
file and edit it such that the contents are as shown below.Now, make sure all of the dependencies (Clojure) are available.
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 namedcom.domain.tiny
with a single static method calledbinomial
, a function taking two integer arguments and returning a double. There are two similarly named functionsbinomial
, 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.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.
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
Now create a file with some meta-information to add to the jar we want to build. In
Manifest.txt
, add the following textNow package it all up into one big jar file, including our Clojure program and the Clojure jar.
To run the program:
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.
As of Clojure 1.6.0, there is a new preferred way to load and invoke Clojure functions. This method is now preferred to calling RT directly (and supersedes many of the other answers here). The javadoc is here - the main entry point is
clojure.java.api.Clojure
.To lookup and call a Clojure function:
Functions in
clojure.core
are automatically loaded. Other namespaces can be loaded via require:IFn
s can be passed to higher order functions, e.g. the example below passesplus
toread
:Most
IFn
s in Clojure refer to functions. A few, however, refer to non-function data values. To access these, usederef
instead offn
:Sometimes (if using some other part of the Clojure runtime), you may need to ensure that the Clojure runtime is properly initialized - calling a method on the Clojure class is sufficient for this purpose. If you do not need to call a method on Clojure, then simply causing the class to load is sufficient (in the past there has been a similar recommendation to load the RT class; this is now preferred):