Mise à jour : Depuis que cette réponse a été publiée, certains des outils disponibles ont changé. Après la réponse d'origine, il y a une mise à jour comprenant des informations sur la façon de construire l'exemple avec les outils actuels.
Ce n'est pas aussi simple que de compiler dans un fichier jar et d'appeler les méthodes internes. Il semble cependant y avoir quelques astuces pour que tout fonctionne. Voici un exemple de fichier Clojure simple qui peut être compilé dans un fichier 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 vous l'exécutez, vous devriez voir quelque chose comme:
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
Et voici un programme Java qui appelle la -binomial
fonction dans le 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));
}
}
Sa sortie est:
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
Le premier élément de magie consiste à utiliser le :methods
mot - clé dans la gen-class
déclaration. Cela semble nécessaire pour vous permettre d'accéder à la fonction Clojure quelque chose comme des méthodes statiques en Java.
La deuxième chose est de créer une fonction wrapper qui peut être appelée par Java. Notez que la deuxième version de -binomial
a un tiret devant.
Et bien sûr, le pot Clojure lui-même doit être sur le chemin des classes. Cet exemple utilise le jar Clojure-1.1.0.
Mise à jour : cette réponse a été retestée à l'aide des outils suivants:
- Clojure 1.5.1
- Leiningen 2.1.3
- JDK 1.7.0 mise à jour 25
La partie Clojure
Créez d'abord un projet et la structure de répertoires associée à l'aide de Leiningen:
C:\projects>lein new com.domain.tiny
Maintenant, passez au répertoire du projet.
C:\projects>cd com.domain.tiny
Dans le répertoire du projet, ouvrez le project.clj
fichier et modifiez-le de sorte que le contenu soit comme indiqué ci-dessous.
(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)
Maintenant, assurez-vous que toutes les dépendances (Clojure) sont disponibles.
C:\projects\com.domain.tiny>lein deps
Vous pouvez voir un message sur le téléchargement du bocal Clojure à ce stade.
Modifiez maintenant le fichier Clojure de C:\projects\com.domain.tiny\src\com\domain\tiny.clj
sorte qu'il contienne le programme Clojure indiqué dans la réponse d'origine. (Ce fichier a été créé lorsque Leiningen a créé le projet.)
Une grande partie de la magie ici est dans la déclaration d'espace de noms. Le :gen-class
dit au système de créer une classe nommée com.domain.tiny
avec une seule méthode statique appelée binomial
, une fonction prenant deux arguments entiers et retournant un double. Il existe deux fonctions nommées de manière similaire binomial
, une fonction Clojure traditionnelle -binomial
et un wrapper accessible depuis Java. Notez le trait d'union dans le nom de la fonction -binomial
. Le préfixe par défaut est un trait d'union, mais il peut être changé en autre chose si vous le souhaitez. La -main
fonction fait juste quelques appels à la fonction binomiale pour s'assurer que nous obtenons les bons résultats. Pour ce faire, compilez la classe et exécutez le programme.
C:\projects\com.domain.tiny>lein run
Vous devriez voir la sortie affichée dans la réponse originale.
Maintenant, emballez-le dans un bocal et placez-le dans un endroit pratique. Copiez le pot Clojure là aussi.
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 partie Java
Leiningen a une tâche intégrée lein-javac
, qui devrait pouvoir aider à la compilation Java. Malheureusement, il semble être cassé dans la version 2.1.3. Il ne peut pas trouver le JDK installé et il ne peut pas trouver le référentiel Maven. Les chemins vers les deux ont des espaces intégrés sur mon système. Je suppose que c'est le problème. Tout IDE Java peut également gérer la compilation et le packaging. Mais pour ce post, nous allons à l'ancienne et le faisons en ligne de commande.
Créez d'abord le fichier Main.java
avec le contenu affiché dans la réponse d'origine.
Pour compiler la partie Java
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
Créez maintenant un fichier avec des méta-informations à ajouter au fichier jar que nous voulons construire. Dans Manifest.txt
, ajoutez le texte suivant
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
Maintenant, regroupez tout dans un gros fichier jar, y compris notre programme Clojure et le fichier 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
Pour exécuter le programme:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
La sortie est essentiellement identique à celle produite par Clojure seul, mais le résultat a été converti en un double Java.
Comme mentionné, un IDE Java s'occupera probablement des arguments de compilation désordonnés et de l'empaquetage.