Java에서 clojure 호출
"java"에대한 히트 이므로 "calling clojure from java" 사용을 합니다.clojure.lang.RT
이치노Clojure 프로젝트에서 이미 jar를 만들어 클래스 패스에 포함시켰다고 가정하고 Java에서 Clojure를 호출하는 방법을 명확하게 설명해 주시겠습니까?
업데이트: 이 답변이 게시된 이후 사용 가능한 도구 중 일부가 변경되었습니다.원래 답변 뒤에 현재 도구를 사용하여 예를 작성하는 방법에 대한 정보가 포함된 업데이트가 있습니다.
이것은 단지로 컴파일하여 내부 메서드를 호출하는 것만큼 간단하지 않습니다.하지만 이 모든 것을 성공시키기 위한 몇 가지 요령이 있는 것 같습니다.다음은 항아리로 컴파일할 수 있는 간단한 Clojure 파일의 예입니다.
(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)))
)
실행하면 다음과 같은 메시지가 나타납니다.
(binomial 5 3): 10
(binomial 10042 111): 49068389575068144946633777...
자바 이 프로그램은 ★★★★★★★★★★★★★★★★★★★.-binomial
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));
}
}
출력은 다음과 같습니다.
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
은 '마법의 한 조각'을하는 것입니다.:methods
합니다.gen-class
은 한 것 같습니다.Java의 정적 메서드와 같은 Clojure 함수에 액세스하기 위해서는 이것이 필요한 것 같습니다.
두 번째는 자바에서 호출할 수 있는 래퍼 함수를 만드는 것입니다.의 두 은 " " " 입니다.-binomial
앞에 대시가 있어요.
그리고 물론 클로주르 항아리 자체는 수업의 길에 있을 것이다.이 예에서는 Clojure-1.1.0 jar를 사용하고 있습니다.
업데이트: 이 답변은 다음 도구를 사용하여 재테스트되었습니다.
- 클로저 1.5.1
- 레이닝겐 2.1.3
- JDK 1.7.0 업데이트 25
클로저 파트
먼저 Leiningen을 사용하여 프로젝트 및 관련 디렉토리 구조를 만듭니다.
C:\projects>lein new com.domain.tiny
이제 프로젝트 디렉토리로 변경합니다.
C:\projects>cd com.domain.tiny
디렉토리에서 " " " 를 .project.clj
다음과 같이 파일을 작성하여 편집합니다.
(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)
이제 모든 종속성(Clojure)을 사용할 수 있는지 확인합니다.
C:\projects\com.domain.tiny>lein deps
이 시점에서 Clojure jar 다운로드에 대한 메시지가 표시될 수 있습니다.
파일을 합니다.C:\projects\com.domain.tiny\src\com\domain\tiny.clj
때
여기서의 마법의 대부분은 네임스페이스 선언에 있습니다.:gen-class
는, 「」을 합니다.com.domain.tiny
「스태틱」이라고 하는 의 스태틱 하고 있습니다.binomial
두 정수 인수를 사용하고 두 개의 인수를 반환하는 함수입니다.의 함수는 두 .binomial
인 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,-binomial
Java ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」해 주세요.-binomial
기본 프리픽스는 하이픈이지만 필요에 따라 다른 프레픽스로 변경할 수 있습니다.-main
함수는 올바른 결과를 얻기 위해 이항 함수에 대해 몇 개의 호출만 할 뿐입니다.그러기 위해서는 클래스를 컴파일하고 프로그램을 실행합니다.
C:\projects\com.domain.tiny>lein run
원래의 회답에 표시된 출력이 표시됩니다.
이제 병에 포장해서 편리한 곳에 두세요.거기에도 클로주르 병을 복사해.
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.
자바 파트
되어 있습니다.lein-javac
Java ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」유감스럽게도 버전 2.1.3에서는 파손된 것 같습니다.Maven Maven의 JDK입니다.두 경로 모두 시스템에 내장된 공간이 있습니다.★★★★★★★★★★★★★★★★★★★★★★★★★★★Java IDE를 사용합니다.하지만 이 직책을 위해, 우리는 구식으로 명령 라인에서 그것을 할 것이다.
파일을 .Main.java
원답에 기재되어 있는 내용으로 합니다.
Java 파트를 컴파일하려면
javac -g -cp target\com.domain.tiny-0.1.0-SNAPSHOT.jar -d target\src\com\domain\Main.java
이제 메타 정보가 포함된 파일을 생성하여 빌드할 jar에 추가합니다. »Manifest.txt
다음
Class-Path: lib\com.domain.tiny-0.1.0-SNAPSHOT.jar lib\clojure-1.5.1.jar
Main-Class: Main
이제 우리 클로저 프로그램과 클로저 항아리를 포함한 큰 항아리 파일로 모두 포장하세요.
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
프로그램을 실행하려면:
C:\projects\com.domain.tiny\target>java -jar Interop.jar
(binomial 5 3): 10.0
(binomial 10042, 111): 4.9068389575068143E263
이 출력은 Clojure에서만 생성되는 출력과 기본적으로 동일하지만 결과는 Java 더블로 변환되었습니다.
앞서 말한 바와 같이 Java IDE는 복잡한 컴파일 인수와 패키징을 처리합니다.
Clojure 1.6.0부터는 Clojure 함수를 로드하고 호출하는 새로운 선호 방법이 있습니다.현재 이 방법은 RT에 직접 콜하는 것보다 선호되고 있습니다(여기에서는 다른 응답보다 우선합니다).javadoc은 여기에 있습니다.주요 진입점은clojure.java.api.Clojure
.
Clojure 함수를 검색 및 호출하려면:
IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);
능능의 clojure.core
자동으로 로드됩니다.다른 네임스페이스는 다음과 같은 방법으로 로드할 수 있습니다.
IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));
IFn
할 수 를 들어, 예에서는 s를 통과시킵니다. 예를 들어, 아래 예시는 통과됩니다.plus
로로 합니다.read
:
IFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));
많이요.IFn
클로주르 스 ★★★★★★★★★★★★★★★★★★★★★★★★★★.그러나 일부에서는 기능하지 않는 데이터 값을 참조합니다. , 「」를 합니다.deref
fn
:
IFn printLength = Clojure.var("clojure.core", "*print-length*");
IFn deref = Clojure.var("clojure.core", "deref");
deref.invoke(printLength);
(Clojure 런타임의 다른 부분을 사용하는 경우) Clojure 런타임의 적절한 초기화가 필요할 수 있습니다.Clojure 클래스에서 메서드를 호출하면 충분합니다.Clojure에서 메서드를 호출할 필요가 없는 경우 클래스를 로드하는 것만으로 충분합니다(과거에는 RT 클래스를 로드하는 유사한 권장 사항이 있었습니다.이 방법이 권장됩니다).
Class.forName("clojure.java.api.Clojure")
편집 이 답변은 2010년에 작성되어 그 당시에 유효했습니다.보다 현대적인 솔루션에 대해서는 Alex Miller의 답변을 참조하십시오.
Java에서 호출하는 코드는 무엇입니까?gen-class를 사용하여 생성된 클래스가 있는 경우 해당 클래스를 호출하기만 하면 됩니다.스크립트에서 함수를 호출하려면 다음 예를 참조하십시오.
문자열에서 코드를 평가하려면 Java 내에서 다음 코드를 사용할 수 있습니다.
import clojure.lang.RT;
import clojure.lang.Var;
import clojure.lang.Compiler;
import java.io.StringReader;
public class Foo {
public static void main(String[] args) throws Exception {
// Load the Clojure script -- as a side effect this initializes the runtime.
String str = "(ns user) (defn foo [a b] (str a \" \" b))";
//RT.loadResourceScript("foo.clj");
Compiler.load(new StringReader(str));
// Get a reference to the foo function.
Var foo = RT.var("user", "foo");
// Call it!
Object result = foo.invoke("Hi", "there");
System.out.println(result);
}
}
편집: 나는 거의 3년 전에 이 답을 썼다.Clojure 1.6에는 Java에서 Clojure를 호출하기 위한 적절한 API가 있습니다.최신 정보에 대한 Alex Miller의 답변을 부탁드립니다.
2011년 원본 답변:
제가 보기에 가장 간단한 방법(AOT 컴파일로 클래스를 생성하지 않는 경우)은 clojure.lang을 사용하는 것입니다.클로저 기능에 액세스하기 위한 RT.이것으로 Clojure에서 했을 일을 흉내낼 수 있습니다(특별한 방법으로 컴파일할 필요가 없습니다).
;; Example usage of the "bar-fn" function from the "foo.ns" namespace from Clojure
(require 'foo.ns)
(foo.ns/bar-fn 1 2 3)
자바어:
// Example usage of the "bar-fn" function from the "foo.ns" namespace from Java
import clojure.lang.RT;
import clojure.lang.Symbol;
...
RT.var("clojure.core", "require").invoke(Symbol.intern("foo.ns"));
RT.var("foo.ns", "bar-fn").invoke(1, 2, 3);
자바에서는 좀 더 장황하지만 코드 조각이 동등하다는 것이 분명했으면 합니다.
Clojure와 Clojure 코드의 소스 파일(또는 컴파일된 파일)이 클래스 경로에 있는 한 이 기능은 작동합니다.
Clartaq의 답변에는 동의하지만, 초보자도 사용할 수 있다고 느꼈습니다.
- 실제 실행 방법에 대한 단계별 정보
- Clojure 1.3 및 Leiningen의 최신 버전에 대한 정보입니다.
- 주 기능을 포함하는 Clojure 항아리로 독립 실행하거나 라이브러리로 연결할 수 있습니다.
그래서 저는 이 블로그 포스트에서 그 모든 것을 다루었습니다.
Clojure 코드는 다음과 같습니다.
(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." ))
lineen 1.7.1 프로젝트 설정은 다음과 같습니다.
(defproject ThingOne "1.0.0-SNAPSHOT"
:description "Hello, Clojure"
:dependencies [[org.clojure/clojure "1.3.0"]]
:aot [ThingOne.core]
:main ThingOne.core)
Java 코드는 다음과 같습니다.
import ThingOne.*;
class HelloJava {
public static void main(String[] args) {
System.out.println("Hello from Java!");
core.foo (12345);
}
}
또는 이 프로젝트의 모든 코드를 github에서 가져올 수도 있습니다.
이것은 Clojure 1.5.0에서 동작합니다.
public class CljTest {
public static Object evalClj(String a) {
return clojure.lang.Compiler.load(new java.io.StringReader(a));
}
public static void main(String[] args) {
new clojure.lang.RT(); // needed since 1.5.0
System.out.println(evalClj("(+ 1 2)"));
}
}
Java 어플리케이션에서 Clojure를 사용하여 빌드된 JAR을 포함하는 경우 두 월드 간의 인터페이스를 위한 별도의 네임스페이스를 갖는 것이 유익하다는 것을 알게 되었습니다.
(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)))
코어 네임스페이스는 주입된 인스턴스를 사용하여 다음 작업을 수행할 수 있습니다.
(ns example-app.core)
(defn send-mails
[{:keys [weather-forecast]}]
(let [temp (.getTemperature weather-forecast)] ...))
테스트 목적으로 인터페이스를 스터브할 수 있습니다.
(example-app.core/send-mails
(reify com.example.WeatherForecast (getTemperature [this] ...)))
JVM 위에 있는 다른 언어에서도 작동하는 다른 기술은 호출하고 싶은 함수에 대한 인터페이스를 선언한 후 '프록시' 함수를 사용하여 해당 함수에 영향을 주는 인스턴스를 만드는 것입니다.
또한 AOT 컴파일을 사용하여 clojure 코드를 나타내는 클래스 파일을 만들 수도 있습니다.이 방법에 대한 자세한 내용은 Clojure API 문서에서 컴파일, gen-class 및 friends에 대한 문서를 참조해 주십시오.그러나 기본적으로 각 메서드 호출에 대해 clojure 함수를 호출하는 클래스를 만듭니다.
또 다른 대안은 새로운 디프로토콜 및 디프티페 기능을 사용하는 것입니다.이 기능은 AOT 컴파일이 필요하지만 더 나은 성능을 제공합니다.자세한 방법은 아직 모릅니다만, 메일링 리스트에 있는 질문이 도움이 될 것 같습니다.
언급URL : https://stackoverflow.com/questions/2181774/calling-clojure-from-java
'programing' 카테고리의 다른 글
Vue 2에서 템플릿을 재사용하려면 어떻게 해야 합니까? (0) | 2022.06.20 |
---|---|
Vue.js 3 속성 '$store'가 'CreateComponentPublicInstance' 유형에 없습니다. (0) | 2022.06.20 |
Vuej 및 부트스트랩 Vue에서 행 편집 (0) | 2022.06.20 |
Java8에서 람다를 사용하여 null이 아닌 경우에만 값 필터링 (0) | 2022.06.20 |
컴파일러가 명백히 초기화되지 않은 변수를 감지하지 못함 (0) | 2022.06.20 |