Invoking Clojure code from Java

Posted: December 24, 2012 in Uncategorized
Tags: , ,

I often see people trying to call Clojure code from Java and having some trouble doing this. So I decided to write a quick utility to do this (inspired by Rich Hickey’s Lightening Talk), and provide a simple example.

The idea is that we use clojure.lang.RT to get access to the key functions that we need to call compile / Clojure code. We do this by setting up some static final variables in Java of type clojure.lang.Var, which we can then invoke to get the required behaviour from Clojure. Setting up these vars looks like this:

import clojure.lang.RT;
import clojure.lang.Symbol;
import clojure.lang.Var;
...
public class Clojure {
 ...
 public static final Var REQUIRE=RT.var("clojure.core", "require");
 ...
}

Once we have the REQUIRE var available, we can invoke it to load any Clojure namespace we need, using code like below:

public static Object require(String nsName) {
  return REQUIRE.invoke(Symbol.intern(nsName));
}

static {
  require("my.special.namespace");
}

I’ve wrapped all this functionality up into a little utility class mikera.cljutils.Clojure, so you can write quick and easy Java apps that call into Clojure as below:


import mikera.cljutils.Clojure;

public class DemoApp {
  public static void main(String [] args) {
    String s = "(+ 1 2)";
    System.out.println("Evaluating Clojure code: "+s);
    Object result=Clojure.eval(s);
    System.out.println("=> "+ result);
  }
}

The utility is available here:

- GitHub site: https://github.com/mikera/clojure-utils

- Compiled version on Clojars: https://clojars.org/net.mikera/clojure-utils

About these ads
Comments
  1. clojurian says:

    Interesting post. It would be cool if the official clojure.jar provided some Java-to-Clojure interop classes. While the direction Clojure->Java is probably more common, it would certainly help to make Clojure more popular if such standard classes existed.

    • Mike says:

      Good idea, something like this would probably make sense in core Clojure. Guess it is a tricky call – how far do you go in providing “convenience methods” since everything is already possible?

  2. clojurian says:

    Suppose you have an awesome Clojure library that you want to use from Java. You could use your Clojure.eval() but it would be nicer to import functions from Clojure into the world of Java and then use them as if they were actual Java objects:

    ClojureFn someCoolClojureLibraryFunction = Clojure.getFunction( “namespace”, “functionname” );

    So that you can just call
    someCoolClojureLibraryFunction.call();

    Another possibility could be that you can retrieve an entire namespace as an object and all functions in that namespace are static methods associated with that namespace-object.

    ClojureNS coolLib = Clojure.getNamespaceObject( “namespace” );
    coolLib.talk_like_a_pirate();

    This (and your Clojure.eval method) are probably the most important parts for Java->Clojure interop.

    • Mike says:

      To some extent you can already do the first approach with the IFn interface and clojure-utils:

      import clojure.lang.IFn;
      ….
      IFn coolFun = Clojure.eval(“my.namespace/my-cool-function”);
      coolFun.invoke(param1,param2);

      • clojurian says:

        Cool. That wasn’t so obvious to me ;)

        Maybe it’s just the “eval is evil” mentality that I have aquired from using other programming languages that prevents me from thinking that eval() is okay for lisp-like languages.

        Your code and your solution are simple but powerful. So it may be a good idea to include it in the official clojure.jar so that Java people will know that they can easily call Clojure code from Java if they need to.

        It’s certainly not much code that is required for Java->Clojure interop but you first need to understand Clojure at a deeper implementation level before you can write an interoperator like your Clojure class. And having an official interoperator could be a good thing. I’d be interested in what other people think about this.

  3. piotrek says:

    in the presentation, Rich Hickey uses REQUIRE.invoke(Symbol.intern(“datomic.query”));
    he does the same for “datomic.peer” and “datomic.function” but not for e.g. “datomic.common” (which is also used in with RT.var). why? when ‘intern’ should be called and when not?

    • mikera7 says:

      intern is just used to create an interned symbol. it’s good practice whenever you want a symbol that is likely to hang around and get re-used a lot (avoids creating new instances all the time).

  4. Will says:

    Thanks for this post! What are the benefits of doing this over exposing java-compatible classes/methods using something like gen-class? Are there performance concerns?

    • mikera7 says:

      gen-class always seems a bit of an ugly solution : it’s an extra build step that always seems to cause extra complexity. I prefer the flexibility of and simplicity dynamically building the namespaces at runtime.

      I don’t think it makes any difference performance wise, though I haven’t benchmarked it yet :-)

  5. Michael Campbell says:

    > gen-class always seems a bit of an ugly solution : it’s an extra build step that always seems to cause extra complexity. I prefer the flexibility of and simplicity dynamically building the namespaces at runtime.

    Doesn’t this break a certain genericity of source though? What I’m wondering here is if there is a way to write clojure code in a polyglot project so that the clojure code can be called from java (or groovy, or scala, …) by simply instantiating a class and calling its methods, like most other JVM stuff. The code should (ideally) be able to be Spring injected as an impl of an interface and called without the caller having to know that it was written in any particular source language.

    Clojure is great for using other languages, but seems less friendly to BE used.

    Or am I totally misreading things here? I’m new at this, so please help me to be smarter on it. Thanks!

    • mikera7 says:

      I think you need to AOT compile your Clojure if you want a specific .class file that can be linked into by other JVM languages.

      However this often isn’t needed: usually it is enough to have Java work via an interface like IFn or IPersistentCollection that are already defined by Clojure. It’s then possible to generate new Clojure objects that implement these interfaces at runtime.

  6. […] post “Invoking Clojure code from Java” demonstrates what I understand to be the “right” way to bring code from a Clojure project into […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s