Calling clojure from java

前端 未结 9 1398
梦毁少年i
梦毁少年i 2020-11-22 11:13

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

相关标签:
9条回答
  • 2020-11-22 11:47

    I agree with clartaq's answer, but I felt that beginners could also use:

    • step-by-step information on how to actually get this running
    • information that's current for Clojure 1.3 and recent versions of leiningen.
    • a Clojure jar that also includes a main function, so it can be run standalone or linked as a library.

    So I covered all that in this blog post.

    The Clojure code looks like this:

    (ns ThingOne.core
     (:gen-class
        :methods [#^{:static true} [foo [int] void]]))
    
    (defn -foo [i] (println "Hello from Clojure. My input was " i))
    
    (defn -main [] (println "Hello from Clojure -main." ))
    

    The leiningen 1.7.1 project setup looks like this:

    (defproject ThingOne "1.0.0-SNAPSHOT"
      :description "Hello, Clojure"
      :dependencies [[org.clojure/clojure "1.3.0"]]
      :aot [ThingOne.core]
      :main ThingOne.core)
    

    The Java code looks like this:

    import ThingOne.*;
    
    class HelloJava {
        public static void main(String[] args) {
            System.out.println("Hello from Java!");
            core.foo (12345);
        }
    }
    

    Or you can also get all the code from this project on github.

    0 讨论(0)
  • 2020-11-22 11:48

    If the use case is to include a JAR built with Clojure in a Java application, I have found having a separate namespace for the interface between the two worlds to be beneficial:

    (ns example-app.interop
      (:require [example-app.core :as core])
    
    ;; This example covers two-way communication: the Clojure library 
    ;; relies on the wrapping Java app for some functionality (through
    ;; an interface that the Clojure library provides and the Java app
    ;; implements) and the Java app calls the Clojure library to perform 
    ;; work. The latter case is covered by a class provided by the Clojure lib.
    ;; 
    ;; This namespace should be AOT compiled.
    
    ;; The interface that the java app can implement
    (gen-interface
      :name com.example.WeatherForecast
      :methods [[getTemperature [] Double]])
    
    ;; The class that the java app instantiates
    (gen-class
      :name com.example.HighTemperatureMailer
      :state state
      :init init
      ;; Dependency injection - take an instance of the previously defined
      ;; interface as a constructor argument
      :constructors {[com.example.WeatherForecast] []}
      :methods [[sendMails [] void]])
    
    (defn -init [weather-forecast]
      [[] {:weather-forecast weather-forecast}])
    
    ;; The actual work is done in the core namespace
    (defn -sendMails
      [this]
      (core/send-mails (.state this)))
    

    The core namespace can use the injected instance to accomplish its tasks:

    (ns example-app.core)
    
    (defn send-mails 
      [{:keys [weather-forecast]}]
      (let [temp (.getTemperature weather-forecast)] ...)) 
    

    For testing purposes, the interface can be stubbed:

    (example-app.core/send-mails 
      (reify com.example.WeatherForecast (getTemperature [this] ...)))
    
    0 讨论(0)
  • 2020-11-22 11:49

    You can also use AOT compilation to create class files representing your clojure code. Read the documentation about compilation, gen-class and friends in the Clojure API docs for the details about how to do this, but in essence you will create a class that calls clojure functions for each method invocation.

    Another alternative is to use the new defprotocol and deftype functionality, which will also require AOT compilation but provide better performance. I don't know the details of how to do this yet, but a question on the mailing list would probably do the trick.

    0 讨论(0)
提交回复
热议问题