Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Update</strong>: 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.</p> <p>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:</p> <pre><code>(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 (&gt; 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))) ) </code></pre> <p>If you run it, you should see something like:</p> <pre><code>(binomial 5 3): 10 (binomial 10042 111): 49068389575068144946633777... </code></pre> <p>And here's a Java program that calls the <code>-binomial</code> function in the <code>tiny.jar</code>.</p> <pre><code>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)); } } </code></pre> <p>It's output is:</p> <pre><code>(binomial 5 3): 10.0 (binomial 10042, 111): 4.9068389575068143E263 </code></pre> <p>The first piece of magic is using the <code>:methods</code> keyword in the <code>gen-class</code> statement. That seems to be required to let you access the Clojure function something like static methods in Java.</p> <p>The second thing is to create a wrapper function that can be called by Java. Notice that the second version of <code>-binomial</code> has a dash in front of it.</p> <p>And of course the Clojure jar itself must be on the class path. This example used the Clojure-1.1.0 jar.</p> <p><strong>Update</strong>: This answer has been re-tested using the following tools:</p> <ul> <li>Clojure 1.5.1</li> <li>Leiningen 2.1.3</li> <li>JDK 1.7.0 Update 25</li> </ul> <p><strong>The Clojure Part</strong></p> <p>First create a project and associated directory structure using Leiningen:</p> <pre><code>C:\projects&gt;lein new com.domain.tiny </code></pre> <p>Now, change to the project directory.</p> <pre><code>C:\projects&gt;cd com.domain.tiny </code></pre> <p>In the project directory, open the <code>project.clj</code> file and edit it such that the contents are as shown below.</p> <pre><code>(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) </code></pre> <p>Now, make sure all of the dependencies (Clojure) are available.</p> <pre><code>C:\projects\com.domain.tiny&gt;lein deps </code></pre> <p>You may see a message about downloading the Clojure jar at this point.</p> <p>Now edit the Clojure file <code>C:\projects\com.domain.tiny\src\com\domain\tiny.clj</code> such that it contains the Clojure program shown in the original answer. (This file was created when Leiningen created the project.)</p> <p>Much of the magic here is in the namespace declaration. The <code>:gen-class</code> tells the system to create a class named <code>com.domain.tiny</code> with a single static method called <code>binomial</code>, a function taking two integer arguments and returning a double. There are two similarly named functions <code>binomial</code>, a traditional Clojure function, and <code>-binomial</code> and wrapper accessible from Java. Note the hyphen in the function name <code>-binomial</code>. The default prefix is a hyphen, but it can be changed to something else if desired. The <code>-main</code> 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.</p> <pre><code>C:\projects\com.domain.tiny&gt;lein run </code></pre> <p>You should see output shown in the original answer.</p> <p>Now package it up in a jar and put it someplace convenient. Copy the Clojure jar there too.</p> <pre><code>C:\projects\com.domain.tiny&gt;lein jar Created C:\projects\com.domain.tiny\target\com.domain.tiny-0.1.0-SNAPSHOT.jar C:\projects\com.domain.tiny&gt;mkdir \target\lib C:\projects\com.domain.tiny&gt;copy target\com.domain.tiny-0.1.0-SNAPSHOT.jar target\lib\ 1 file(s) copied. C:\projects\com.domain.tiny&gt;copy "C:&lt;path to clojure jar&gt;\clojure-1.5.1.jar" target\lib\ 1 file(s) copied. </code></pre> <p><strong>The Java Part</strong></p> <p>Leiningen has a built-in task, <code>lein-javac</code>, 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.</p> <p>First create the file <code>Main.java</code> with the contents shown in the original answer.</p> <p>To compile java part</p> <pre><code>javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java </code></pre> <p>Now create a file with some meta-information to add to the jar we want to build. In <code>Manifest.txt</code>, add the following text</p> <pre><code>Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar Main-Class: Main </code></pre> <p>Now package it all up into one big jar file, including our Clojure program and the Clojure jar.</p> <pre><code>C:\projects\com.domain.tiny\target&gt;jar cfm Interop.jar Manifest.txt Main.class lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar </code></pre> <p>To run the program:</p> <pre><code>C:\projects\com.domain.tiny\target&gt;java -jar Interop.jar (binomial 5 3): 10.0 (binomial 10042, 111): 4.9068389575068143E263 </code></pre> <p>The output is essentially identical to that produced by Clojure alone, but the result has been converted to a Java double.</p> <p>As mentioned, a Java IDE will probably take care of the messy compilation arguments and the packaging.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload