How to: gui: jvm + reflection + swing + scala

Please note:

  • This topic is about “How to do Foo?”
  • This topic is not about “Is Foo a good idea?”
    Therefore, if you believe Foo is a bad idea / Foo can’t be done, please post a separate topic (rather than adding noise here).

I would like to start a thread where we figure out how to automatically generate Elixir bindings to JVM/Swing via Reflection.

At the high level, this involves a few things:

  1. running a JVM/Scala node that acts as an Erlang node [easy, see blelow]
  2. decide on some message format (I have no idea what this is) for creating/deleting GUI elements as well as GUI events
  3. run JVM/Scala program to, via reflection, get a methods of Swing classes
  4. generate Elixir code for [3] that satisfies [2]

The goal here is to (1) get bindings for JVM/Swing and (2) do it automatically via reflection rather than manually. The goal here is that we can iterate on (2, 4) if we are generating bindings via code.

(1) is straight forward, Erlang -- jinterface . I have verified it works via this simple Scala program:

import com.ericsson.otp.erlang.{OtpErlangAtom, OtpErlangObject, OtpErlangPid, OtpErlangTuple, OtpMbox, OtpNode}

object OtpMain {

  def main(args: Array[String]): Unit = {
    val node: OtpNode = new OtpNode("foo")
    val mbox: OtpMbox = node.createMbox()
    mbox.registerName("server")
    
    val msg: Array[OtpErlangObject] = new Array[OtpErlangObject](2)
    msg(0) = mbox.self()
    msg(1) = new OtpErlangAtom("hello, world")
    val tuple: OtpErlangTuple = new OtpErlangTuple(msg)
    
    mbox.send("echo", "foo@localhost", tuple)
    
    val reply: OtpErlangObject = mbox.receive()
    
    var o: OtpErlangObject = null
    var msg2: OtpErlangTuple = null
    var from: OtpErlangPid = null
    
    while (true) {
      try { 
        o = mbox.receive()
        o match {
          case tuple1: OtpErlangTuple =>
            msg2 = tuple1
            from = msg2.elementAt(0).asInstanceOf[OtpErlangPid]
            mbox.send(from, msg2.elementAt(1))
          case _ =>
        }
      } catch { 
        case e: Exception => System.out.println("" + e)
      }
    }
  }
}

If you are versed in JVM/{swing, reflection}, I am interested in hearing your thoughts on how to design the protocol for [2]. The main concern here is that because we do not have “cross language refs/ptrs”, we need some way (perhaps better than a dumb u64) for referring to “this button” or “that text field”, so it is clear when we say things like “this button got clicked” or “user typed ‘a’ in that text field”

If there are JVM/Swing API issues that force certain design decisions for our protocol, I’m interested in hearing about those too.

Lastly, if you are a Scala wizard w/ Reflection and can share some sample code for querying info about Swing, that would be great too.

Thanks!

PS: Java, Kotlin, Clojure solutions welcome too. Converting from one JVM language to another is easier than getting code that works in the first place.