(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))))
@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
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.
The thrown error come from here: https://github.com/hypfvieh/dbus-java/blob/223f9145ca87d55ad0b26c50a118c682124be18f/dbus-java/src/main/java/org/freedesktop/dbus/Marshalling.java#L305
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))))
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)
@emccue How can I run the start function?
just like a normal function
(def o (hello.DBusHelloWorldServer.))
(start o)
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