Search code examples
clojure

Mutating a void returning Java object


Im lost at how to best translate the following Java code to ideomatic Clojure

        var lsClient = new LightstreamerClient(...);
        lsClient.connectionDetails.setUser(...);
        lsClient.connectionDetails.setPassword(...);
        lsClient.addListener(...);
        lsClient.connect();

I have tried multiple things and have ended up with something that does not even compile

(defn create-connection-and-subscriptions!
  [{:keys [identifier cst token ls-endpoint]} callback]
  (let [password (str "CST-" cst "|XST-" token)
        client (LightstreamerClient. ls-endpoint nil)
        connection-listener (client-listener-adapter/create callback)]
    (doseq [c [client]]
      (.setPassword (.-connectionDetails c) password)
      ( .setUser (.-connectionDetails c) identifier)
      (.addListener connection-listener c)
      (.connect c))
    ))

How should I change this for things to work as the Java code. OBS ... in java code is just that I have have removed the input.


Solution

  • What you've written is weird (why doseq over a single item?), but should work. I'd replace (doseq [c [client]] with (let [c client] if you want to do it that way, or just rename the existing variable to c.

    If you want to avoid re-typing the variable name, then doto is the tool for performing multiple side-effecting effects with the same first argument. It's not super clear that this is worth it for objects you only call two methods on, but you could write

    (doto (.-connectionDetails client)
      (.setPassword password)
      (.setUser identifier))
    (doto client
      (.addListener connection-listener)
      (.connect))
    

    If you are truly devoted to doing it all as one expression with no new variables, and don't mind some labyrinthine macro rewriting, you can write this instead:

    (doto (LightstreamerClient. ls-endpoint nil)
      (-> (.-connectionDetails)
          (doto 
            (.setPassword password)
            (.setUser identifier)))
      (.addListener connection-listener)
      (.connect))
    

    I find this rather cute, but code should be written to be readable, not cute, so I don't recommend it. You may enjoy puzzling through how it works, though.