Actualización : desde que se publicó esta respuesta, algunas de las herramientas disponibles han cambiado. Después de la respuesta original, hay una actualización que incluye información sobre cómo construir el ejemplo con las herramientas actuales.
No es tan simple como compilar en un jar y llamar a los métodos internos. Sin embargo, parece haber algunos trucos para que todo funcione. Aquí hay un ejemplo de un archivo Clojure simple que se puede compilar en un 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)))
)
Si lo ejecuta, debería ver algo como:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
Y aquí hay un programa Java que llama a la -binomial
función en el 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));
}
}
Su salida es:
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
La primera pieza de magia es usar la :methods
palabra clave en la gen-class
declaración. Eso parece ser necesario para permitirle acceder a la función Clojure, algo así como métodos estáticos en Java.
Lo segundo es crear una función de contenedor que Java pueda invocar. Observe que la segunda versión de -binomial
tiene un guión delante.
Y, por supuesto, el frasco de Clojure debe estar en el camino de la clase. Este ejemplo utiliza el jar Clojure-1.1.0.
Actualización : esta respuesta se ha vuelto a probar con las siguientes herramientas:
- Clojure 1.5.1
- Leiningen 2.1.3
- JDK 1.7.0 Actualización 25
La parte de Clojure
Primero cree un proyecto y una estructura de directorios asociada usando Leiningen:
C:\projects>lein new com.domain.tiny
Ahora, cambie al directorio del proyecto.
C:\projects>cd com.domain.tiny
En el directorio del proyecto, abra el project.clj
archivo y edítelo de modo que el contenido sea el que se muestra a continuación.
(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)
Ahora, asegúrese de que todas las dependencias (Clojure) estén disponibles.
C:\projects\com.domain.tiny>lein deps
Es posible que vea un mensaje sobre la descarga del jar Clojure en este momento.
Ahora edite el archivo Clojure de C:\projects\com.domain.tiny\src\com\domain\tiny.clj
modo que contenga el programa Clojure que se muestra en la respuesta original. (Este archivo se creó cuando Leiningen creó el proyecto).
Gran parte de la magia aquí está en la declaración del espacio de nombres. El :gen-class
le dice al sistema que cree una clase nombrada com.domain.tiny
con un único método estático llamado binomial
, una función que toma dos argumentos enteros y devuelve un doble. Hay dos funciones con nombres similares binomial
, una función Clojure tradicional -binomial
y un contenedor accesible desde Java. Tenga en cuenta el guión en el nombre de la función -binomial
. El prefijo predeterminado es un guión, pero se puede cambiar a otra cosa si lo desea. La -main
función solo hace un par de llamadas a la función binomial para garantizar que estamos obteniendo los resultados correctos. Para hacer eso, compila la clase y ejecuta el programa.
C:\projects\com.domain.tiny>lein run
Debería ver la salida que se muestra en la respuesta original.
Ahora empaquételo en un frasco y colóquelo en un lugar conveniente. Copie el frasco de Clojure allí también.
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.
La parte de Java
Leiningen tiene una tarea incorporada lein-javac
, que debería poder ayudar con la compilación de Java. Desafortunadamente, parece estar roto en la versión 2.1.3. No puede encontrar el JDK instalado y no puede encontrar el repositorio de Maven. Los caminos a ambos tienen espacios incrustados en mi sistema. Supongo que ese es el problema. Cualquier IDE de Java también podría manejar la compilación y el empaquetado. Pero para esta publicación, vamos a la vieja escuela y lo hacemos en la línea de comando.
Primero cree el archivo Main.java
con el contenido que se muestra en la respuesta original.
Para compilar parte de Java
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
Ahora cree un archivo con alguna metainformación para agregar al jar que queremos construir. En Manifest.txt
, agregue el siguiente texto
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
Ahora empaquete todo en un gran archivo jar, incluido nuestro programa Clojure y el jar Clojure.
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
Para ejecutar el programa:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
La salida es esencialmente idéntica a la producida por Clojure solo, pero el resultado se ha convertido en un Java doble.
Como se mencionó, un IDE de Java probablemente se encargará de los argumentos de compilación desordenados y el empaquetado.