Fork me on GitHub
Michaël Salihi19:11:18

Hi everybody! I tried to figurate out to how interop with java-dbus library. Which options Clojure offers for converting this Java snippet to Clojure:

import org.freedesktop.dbus.DBusInterface;

public class DBusHelloWorldServer implements DBusInterface {
     dbusConnection.exportObject("/Main", this);

Michaël Salihi19:11:39

I toying with Reify, Proxy but I can't figure out how to create the object to put at the exportObject method second argument.

Alex Miller (Clojure team)19:11:00

reify methods all take "this" as the first argument

Alex Miller (Clojure team)19:11:42

(reify DBusInterface (some-method [this conn] (.exportObject conn "/Main" this)))

👍 3
Alex Miller (Clojure team)19:11:12

no reason to use proxy here afaict

Michaël Salihi19:11:51

Thx @alexmiller for the confirmation! I'm starting to see more clearly how to do it.

Alex Miller (Clojure team)19:11:11

if you want to utilize extending from AbstractConnection, that's where you'd need a proxy

👍 3
Michaël Salihi19:11:57

I put all the java code here for the context:

package hello;

import org.freedesktop.dbus.DBusInterface;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.exceptions.DBusException;

public class DBusHelloWorldServer implements DBusInterface
    private DBusConnection dbusConnection;

    public boolean isRemote()
        return false;

    private boolean stop=false;

    public String helloWorld(String name)
        return "Hello World : "+name;

    public void start()
                dbusConnection = DBusConnection.getConnection(DBusConnection.SESSION);
                dbusConnection.exportObject("/Main", this);
                while (!stop)
                        try {
                        } catch (Exception e) {}
        catch (DBusException e)

    public static void main(String[] args)
        new DBusHelloWorldServer().start();

Alex Miller (Clojure team)19:11:19

given that you have state (the stop field), I'd probably make a deftype that implemented DBusInterface

Michaël Salihi19:11:08

For the moment, I struggle with this interop code which of course does not work and gives me an error on the object to pass as argument:

(ns main.core
  (:import (org.freedesktop.dbus DBusConnection DBusInterface)))

(defn start []
  (let [dbus-conn (. DBusConnection getConnection DBusConnection/SESSION)
        dbus-hello-world-server (reify DBusInterface
                                  (isRemote [this] false))]
    (doto dbus-conn
        (.requestBusName "mon.premier.bus")
        (.exportObject "/Main" dbus-hello-world-server))))

(defn -main []

Alex Miller (Clojure team)19:11:16

is this file the scope of what you're doing? making a main that starts an instance of the server?

Alex Miller (Clojure team)19:11:27

who actually calls helloWorld() ?

Michaël Salihi19:11:48

Yes, I updated the snippet above with all the namespace.

Michaël Salihi19:11:46

And the ouput error: Execution error (DBusException) at org.freedesktop.dbus.Marshalling/recursiveGetDBusType ( Exporting non-exportable type interface clojure.lang.IPersistentMap

Michaël Salihi19:11:03

For the moment, in the Clojure version, my test to interop helloWorld() was unsuccessful.

Alex Miller (Clojure team)19:11:47

there's more going on here under the hood of that exportObject

Michaël Salihi19:11:10

As I understand, DBusInterface contains one method isRemote and with reify it's not possible to adding one, right?

Alex Miller (Clojure team)19:11:21

what does exporting do?

Alex Miller (Clojure team)19:11:59

I assume it's making some assumptions about the object being exported that presumably Clojure is not meeting, but the docs don't say anything useful that I saw

Michaël Salihi19:11:53

@alexmiller thank you for the time you take:+1:

Michaël Salihi19:11:58

This is my first tests with the interop and I think I did not take the easiest haha

Alex Miller (Clojure team)19:11:56

sounds like it's using java reflection on the object to map methods, which might run into some troubles

Alex Miller (Clojure team)19:11:00

and it's expecting a known set of types

Alex Miller (Clojure team)19:11:38

there may be some path through this but I suspect you'll need to understand what export does more deeply

Alex Miller (Clojure team)19:11:05

hard for me to say what is most likely to work

Michaël Salihi20:11:56

> what does exporting do? Do you mean, we should look at the source code?

Michaël Salihi20:11:54

Maybe it can help, client side I use this dbus-send cli to talk with the server:

dbus-send --print-reply --dest='mon.premier.bus' /Main mon.premier.bus.helloWorld string:'Mike'

Alex Miller (Clojure team)20:11:50

my impression is that export-object will inspect the Java object using reflection, find its methods and make them available to call

Alex Miller (Clojure team)20:11:16

it's most likely finding stuff you don't want (and there is no actual method that you do want yet)

Alex Miller (Clojure team)20:11:10

so reify is probably not the answer - you'll most likely need gen-class to generate the class with the methods you want to call, but you might also need to use definterface or gen-interface to construct the interface that instance implements

Alex Miller (Clojure team)20:11:29

understanding exactly what export-object does would help guide that

Alex Miller (Clojure team)20:11:44

not sure I can be any more help on this atm

Michaël Salihi20:11:40

You have already helped / guided me well, that's perfect. Thanks again Alex.