04
Jun 25

Calling Scala Objects from JRuby in Java21

I’ve just gone a bit doo-lally figuring out how to make this work, so in the interests of saving the next poor git, if you’re upgrading from JRE8 to JRE21, JRuby-Scala integration changed and broke a few things. There’s no documentation apart from a single poorly-written line in a wiki page on github about how the change works, so good luck figuring out how this translates to real life examples:

// Add scala aliases for apply/update to roughly equivalent Ruby names
if (name.equals("apply")) {
  addUnassignedAlias("[]", assignedNames, Priority.ALIAS); 

After 223 attempts to call the [] operator in various ways trying to get it to call apply() behind the scenes and about twenty other approaches to getting the reference needed, I had to dive into how Scala gets compiled for the JVM, find that when the Scala code is for a Scala Object with a companion class (so basically a class with an associated singleton object), Scala compiles that to two classes on the JVM, one with the original name from the Scala code and one with a postfix’d dollarsign symbol.

To get the singleton reference for a Scala Object when it has a companion class, you need to access the MODULE$ field in the class with the $ postfix, but you can’t just call for that in JRuby as $ is a special character for accessing global variables amongst other things, so you have to go round the houses a bit.

It goes from this in JRE8 (actual package and class names changed to protect the guilty):

Foo::Bar.apply.addListener(self)

to this mess in JRE21:

bob = 'Java::Foo::Bar$'.split('::').inject(Object) { |n, c| n.const_get c }
fred = bob.java_class.get_field('MODULE$').get(nil)
fred.apply.addListener(self)

But, it works, and fred.apply gets back to the Object so you can call addListener() and register your callback function (this is from some inhouse library code, which looks like this, but obviously changed to skirt NDAs):

object Bar {
  private val A = new BarImpl
  def apply(): Bar = A
}

private[kafka] class BarImpl extends Bar {
  //Lots of internal guff redacted including a list of listeners
  @PublicAPI
  def addListener(listener: ListenerThingy) {
    val exists = listeners.contains(listener)
    if (!exists) {
      listeners.add(listener)
      notifyOtherThings(listener)
    }
  }

Next time, I choose an easier language. Like, say, assembler.


15
Jan 25

Turning an xmas tree

Recorded turning one for reference for when I have to do it next year and can’t remember all the details 😀 This was one of the finished ones, but the unfinished ones (no wax, just sanded) are nicer for kids as they can colour them in with markers or paints themselves.

Nearly had a woopsie on this one when I didn’t notice the rest moving…


14
Jan 25

Solstice turning

Got back to some woodturning over solstice. Been a while, out of practice. The skew catches were… good substitutes for a large cup of coffee. But things came out in the end.

Continue reading →