Llamando a Clojure desde Java


Answers

A partir de Clojure 1.6.0, hay una nueva forma preferida de cargar e invocar las funciones de Clojure. Ahora se prefiere este método para llamar a RT directamente (y reemplaza a muchas otras respuestas aquí). El javadoc está here - el principal punto de entrada es clojure.java.api.Clojure .

Para buscar y llamar a una función de Clojure:

IFn plus = Clojure.var("clojure.core", "+");
plus.invoke(1, 2);

Las funciones en clojure.core se cargan automáticamente. Otros espacios de nombres se pueden cargar a través de require:

IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));

IFn se pueden pasar a funciones de orden superior, por ejemplo, el siguiente ejemplo pasa plus para read :

IFn map = Clojure.var("clojure.core", "map");
IFn inc = Clojure.var("clojure.core", "inc");
map.invoke(inc, Clojure.read("[1 2 3]"));

La mayoría de los IFn en Clojure se refieren a las funciones. Algunos, sin embargo, se refieren a valores de datos no funcionales. Para acceder a estos, use deref lugar de fn :

IFn printLength = Clojure.var("clojure.core", "*print-length*");
IFn deref = Clojure.var("clojure.core", "deref");
deref.invoke(printLength);

Algunas veces (si usa alguna otra parte del tiempo de ejecución de Clojure), es posible que deba asegurarse de que el tiempo de ejecución de Clojure esté correctamente inicializado. Llamar a un método en la clase Clojure es suficiente para este propósito. Si no necesita llamar a un método en Clojure, basta con simplemente hacer que la clase se cargue (en el pasado hubo una recomendación similar para cargar la clase RT, que ahora se prefiere):

Class.forName("clojure.java.api.Clojure") 
Question

La mayoría de los principales éxitos de google para "llamar a clojure desde Java" están desactualizados y recomendamos usar clojure.lang.RT para compilar el código fuente. ¿Podría ayudar con una explicación clara de cómo llamar a Clojure desde Java suponiendo que ya ha creado un contenedor del proyecto Clojure y lo incluyó en el classpath?




EDITAR: Escribí esta respuesta hace casi tres años. En Clojure 1.6 hay una API adecuada exactamente con el propósito de llamar a Clojure desde Java. Por favor, la respuesta de Alex Miller para obtener información actualizada: https://.com/a/23555959/202121

Respuesta original de 2011:

Tal como lo veo, la forma más simple (si no se genera una clase con compilación AOT) es usar clojure.lang.RT para acceder a funciones en clojure. Con él puedes imitar lo que hubieras hecho en Clojure (sin necesidad de compilar las cosas de manera especial):

;; Example usage of the "bar-fn" function from the "foo.ns" namespace from Clojure
(require 'foo.ns)
(foo.ns/bar-fn 1 2 3)

Y en Java:

// 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);

Es un poco más detallado en Java, pero espero que quede claro que los fragmentos de código son equivalentes.

Esto debería funcionar siempre que Clojure y los archivos fuente (o archivos compilados) de su código Clojure estén en el classpath.




Esto funciona con 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)"));
    }
}



Otra técnica que funciona también con otros lenguajes sobre JVM es declarar una interfaz para las funciones que desea llamar y luego usar la función 'proxy' para crear una instancia que las implemente.






Links