Calling clojure from java.

134 views
Skip to first unread message

mmwaikar

unread,
Jul 26, 2011, 1:43:31 AM7/26/11
to clo...@googlegroups.com
Hi,

I am using the Lobos library - https://github.com/budu/lobos
In it there's a function create, which is called like this - (create db (table :some-name)), where db is earlier defined as - (def db
     {:classname "org.postgresql.Driver"
      :subprotocol "postgresql"
      :user "postgres"
      :password ""
      :subname "//localhost:5432/flyway"})

If I have to call the above function from Java, how do I -
1) define the def (do I have to load some variable)?
2) I am loading the reqd. lobos libraries using [ RT.load("lobos/core", true); ] and then getting the reference to the create function like - [ Var foo = RT.var("lobos.core", "create"); ]
    But how do I pass the required arguments to this function. Do I need to create an array?

Any help is truly appreciated.

Thanks,
Manoj.

Meikel Brandmeyer

unread,
Jul 26, 2011, 2:19:01 AM7/26/11
to clo...@googlegroups.com
Hi,

you should go through the normal Clojure Vars to access the functions. To actually call the functions you use invoke. Note: table is a macro, so you can't call it directly. You have to use the table* function and do any sugar provided by the table macro yourself. Here is an example how this could look like:

import clojure.lang.RT;
import clojure.lang.Var;

public class Foo {
    // Required core functions.
    static final Var symbol = RT.var("clojure.core", "symbol");
    static final Var require = RT.var("clojrue.core", "require");
    static final Var keyword = RT.var("clojure.core", "keyword");

    static {
        require.invoke(symbol.invoke("lobos.core"));

        static final Var create = RT.var("lobos.core", "create");
        static final Var table = RT.var("lobos.core", "table*");
    }

    void frobnicate() {
        final Object db = RT.map(
                keyword.invoke("classname"),   "org.postgresql.Driver",
                keyword.invoke("subprotocol"), "postgresql",
                keyword.invoke("user"),        "postgres",
                keyword.invoke("password"),    "",
                keyword.invoke("subname"),     "//localhost:5432/flyway"
        );

        create.invoke(db, table.invoke(keyword.invoke("some-name")));
    }
}

Untested, though.

Sincerely
Meikel

Petr Gladkikh

unread,
Jul 26, 2011, 2:19:20 AM7/26/11
to clo...@googlegroups.com
You might look at examples here
http://en.wikibooks.org/wiki/Clojure_Programming/Tutorials_and_Tips#Invoking_Clojure_from_Java

If i were doing same thing I would put all necessary initalization
into a Clojure script and wrapped necessary functions to have less
arguments to pass from Java.
This way later you'll need to load single script only. Say

(ns
(use lobos.core))
(def db {.....})
(defn create2 [table-name] (create db (table table-name)))

This might not be convenient in your case however.

--
Petr Gladkikh

mmwaikar

unread,
Jul 26, 2011, 1:48:08 PM7/26/11
to clo...@googlegroups.com
Thanks Meikel, I tried the below stuff -

package com.codionics.flyway;

import clojure.lang.RT;
import clojure.lang.Var;

public class wrapper {


    static final Var symbol = RT.var("clojure.core", "symbol");
    static final Var require = RT.var("clojrue.core", "require");
    static final Var keyword = RT.var("clojure.core", "keyword");
       
    static final Var create = RT.var("lobos.core", "create");
    static final Var table = RT.var("lobos.schema", "table*");
    static final Var debuglevel = RT.var("lobos.core", "set-debug-level");

    static Object db;
   
    public static void createTable() {
          
        try {
            RT.load("lobos/core", true);
            RT.load("lobos/schema", true);

                       
        db = RT.map(
                keyword.invoke("classname"),   "org.postgresql.Driver",
                keyword.invoke("subprotocol"), "postgresql",
                keyword.invoke("user"),        "postgres",
                keyword.invoke("password"),    "lindb2011",

                keyword.invoke("subname"),     "//localhost:5432/flyway"
        );           
           
            Object result = create.invoke(db, table.invoke(keyword.invoke("music")));
            System.out.println(result);
           
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    };
}

and called wrapper.createTable() then I get - (#<core$create_STAR_ lobos.core$create_STAR_@49431028> (quote {:classname "org.postgresql.Driver", :subprotocol "postgresql", :user "postgres", :password "lindb2011", :subname "//localhost:5432/flyway"}))

I really don't understand the output, but it is definitely not what I am expecting.

Please let me know.

Thanks Petr, I have gone through that link, and I'll try this approach if the first one doesn't work.

Regards,
Manoj.

Meikel Brandmeyer

unread,
Jul 26, 2011, 2:15:58 PM7/26/11
to clo...@googlegroups.com
Hi,

Am 26.07.2011 um 19:48 schrieb mmwaikar:

> RT.load("lobos/core", true);
> RT.load("lobos/schema", true);

You should go through require.invoke(). Not RT.load().

> and called wrapper.createTable() then I get - (#<core$create_STAR_ lobos.core$create_STAR_@49431028> (quote {:classname "org.postgresql.Driver", :subprotocol "postgresql", :user "postgres", :password "lindb2011", :subname "//localhost:5432/flyway"}))
>
> I really don't understand the output, but it is definitely not what I am expecting.

create is obviously also a macro. You'll have to use create*.

Sincerely
Meikel

mmwaikar

unread,
Jul 28, 2011, 1:43:04 PM7/28/11
to clo...@googlegroups.com
Thanks again Meikel. Where can I read about things like bindRoot, intern or to be precise java-clojure interop?

Meikel Brandmeyer

unread,
Jul 28, 2011, 1:58:55 PM7/28/11
to clo...@googlegroups.com
Hi,

Am 28.07.2011 um 19:43 schrieb mmwaikar:

> Thanks again Meikel. Where can I read about things like bindRoot, intern or to be precise java-clojure interop?

There are only a few things you must know:

- RT.var to get a variable from a namespace
- v.invoke to invoke a function stored in a Var

That's it. Then do the normal clojure stuff. bindRoot, intern and such are none of our concerns. (I don't know anything about them, either.)

So to load a namespace, you would say in Clojure:

(require 'some.name.space)

In Java, you to the same with more boilerplate:

RT.var("clojure.core", "require").invoke(RT.var("clojure.core", "symbol").invoke("some.name.space"))

This is my last information on how the officially blessed way to interface with Clojure from Java looks like. I'm not sure about RT.map.

If the thing you want to call is a macro, you have to hope that the library other provided the logic as star function (as in Nicolas' case). If there is no function containing the actual logic, you have to re-implement the macro in Java. cf. http://stackoverflow.com/questions/6672934/how-to-call-clojure-macros-from-java/6674923#6674923

Sincerely
Meikel

.Bill Smith

unread,
Jul 28, 2011, 2:07:20 PM7/28/11
to clo...@googlegroups.com
It may also be useful to read up on primitives, since primitive support is often a source of impedance mismatch when software in one language talks to software in another.  Would someone mind supplying a link to a description of how Clojure works with Java primitives in the 1.2.1 and 1.3 releases?

Bill

Ken Wesson

unread,
Jul 28, 2011, 7:55:28 PM7/28/11
to clo...@googlegroups.com
On Thu, Jul 28, 2011 at 1:58 PM, Meikel Brandmeyer <m...@kotka.de> wrote:
> If the thing you want to call is a macro, you have to hope that the library other provided the logic as star function (as in Nicolas' case). If there is no function containing the actual logic, you have to re-implement the macro in Java. cf. http://stackoverflow.com/questions/6672934/how-to-call-clojure-macros-from-java/6674923#6674923

There's also the eval(read(whatever)) route, if you need to resort to it.

--
Protege: What is this seething mass of parentheses?!
Master: Your father's Lisp REPL. This is the language of a true
hacker. Not as clumsy or random as C++; a language for a more
civilized age.

Reply all
Reply to author
Forward
0 new messages