java 2020-11-17

Thx @emccue for the help and for showing me the gen-class direction!

in your first draft, I don't see what to put for the server argument that the different functions take. I see swap and deref, so I should put server value in an atom..but how can I assoc the current class object who implements DBusInterface in it?

OK, I read the gen-class doc, the first param is the current object "this" as I understand. When I try to run start , I have this error:

user=> (def o (hello.DBusHelloWorldServer.))
#'user/o
user=> (.start o)
#object[hello.DBusHelloWorldServer 0x57e388c3 hello.DBusHelloWorldServer@57e388c3]
org.freedesktop.dbus.exceptions.DBusException: Exporting non-exportable type class java.lang.Object

Same error as with my tests with Reify. You can see the object on the REPL block above, I made a println.

Visibly the Clojure gen-class object return false when testing with isAssignableFrom

> so I should put server value in an atom..but how can I assoc the current class object who implements DBusInterface in it?

well, an atom is just one option, but here

(defn -start [server]
  (try 
    (let [dbus-connection (DBusConnection/getConnection DBusConnection/SESSION)]
      (swap! (.state server) assoc ::dbus-connection dbus-connection)
      (.requestBusName "mon.premier.bus")
      (.exportObject "/Main" server)
      (while (not (::stop @(.state server))
        (try 
          (Thread/sleep 1000)
          (catch Exception e nil)))
        (.disconnect dbus-connection)))
    (catch DBusException e
      (.printStackTrace e))))

you can swap it in

and i might have named that kinda wierd

(defn start [server]
  (try 
    (let [dbus-connection (DBusConnection/getConnection DBusConnection/SESSION)]
      (swap! (.state server) assoc ::dbus-connection dbus-connection)
      (.requestBusName "mon.premier.bus")
      (.exportObject "/Main" server)
      (while (not (::stop @(.state server))
        (try 
          (Thread/sleep 1000)
          (catch Exception e nil)))
        (.disconnect dbus-connection)))
    (catch DBusException e
      (.printStackTrace e))))

@emccue How can I run the start function?

just like a normal function

(def o (hello.DBusHelloWorldServer.))

you need to be in the namespace where the function is or require it though

so if you add a (require '[hello :refer :all]) to your repl session that works. You can also switch to the other ns after loading in the file (which will use in-ns but how to hot load is slightly dependent on your tool)

OK, thank you, I still have trouble thinking with interop 🙂

I have always the same error:

Honestly this is the absolute ugliest path with interop. It would maybe be more convenient to just write a java interface and implement in clojure

okay so that wasn't an issue

what does (ancestors hello.DBusHelloWorldServer) get you?

I get a set #{java.lang.Object org.freedesktop.dbus.DBusInterface}

@emccue Do you know how can I compare with the Java version? The ancestors object?

ancestors can take any java class and give you that set

so if you can compile and import your java version (in a diff package or whatever), then you can compare stuff about them

i'm somewhat at a loss for whats going wrong

since if it fails at that isAssignableFrom part, it doesn't make sense, since you do implement DBusInterface

since I didn't intend start to actually be a method

just a function in clojure

try it without the - and see if it works - maybe gen-class tried to translate that as a method and it couldn't be exported?

and the class implements DBusInterface

CLASS_TO_ARGUMENTTYPE.put(DBusInterface.class, Message.ArgumentType.OBJECT_PATH);
        CLASS_TO_ARGUMENTTYPE.put(DBusPath.class, Message.ArgumentType.OBJECT_PATH);
        CLASS_TO_ARGUMENTTYPE.put(ObjectPath.class, Message.ArgumentType.OBJECT_PATH);
    }

for (Entry<Class<?>, Byte> entry : CLASS_TO_ARGUMENTTYPE.entrySet()) {
                    if (entry.getKey().isAssignableFrom(dataTypeClazz)) {

so it should be assignable to that

Thank again @emccue, I'll tried that. (y)

(gen-class
	:name "hello.DBusHelloWorldServer"
	:implements [DBusInterface]
	:state "state"
	:init "init"
    :methods [[helloWorld [String] void]
	:prefix "-")

(defn- -init []
  [[] (atom {::dbus-connection nil
             ::stop false})]

(defn- -isRemote [server]
  false)

(defn- -helloWorld [server name]
  (swap! (.state server) assoc ::stop true)
  (str "Hello World :" name))

(defn -start [server]
  (try 
    (let [dbus-connection (DBusConnection/getConnection DBusConnection/SESSION)]
      (.requestBusName "mon.premier.bus")
      (.exportObject "/Main" server)
      (while (not (::stop @(.state server))
        (try 
          (Thread/sleep 1000)
          (catch Exception e nil)))
        (.disconnect dbus-connection)))
    (catch DBusException e
      (.printStackTrace e))))

👍 1

@admin055 Thats a first stab at it

this is admittedly one of the things clojure has trouble with

since now you will have to add a build step to AOT compile this file

and if you make changes you'll have to restart your repl

but any time you need to make a method that isn't already on an interface you will run into gen-class

you can sidestep that by making an interface for the methods like helloWorld

but this is the direct translation of the java above, more or less