Scala getSimpleName bug causing havoc in jruby

Not a jruby bug, but I’m curious if anyone has ideas on ways to work
around
it in jruby.

Basically, scala creates bad code for doubly nested classes that causes
getSimpleName to blow up. They aren’t fixing it from what I can tell.
I
didn’t hit this bug until I was already deep into using akka on a
project.
I can filter out these bad classes as I find them and keep them out of
jruby, but was hoping someone might have an idea on a cleaner
workaround.

Chris


Link to a scala ticket (one of several) showing the problem:

Sample stacktrace when it hits a bad class:

java.lang.InternalError: Malformed class name
at java.lang.Class.getSimpleName(Class.java:1155)
at org.jruby.javasupport.JavaClass.setupProxy(JavaClass.java:743)
at org.jruby.javasupport.Java.createProxyClass(Java.java:574)
at org.jruby.javasupport.Java.createProxyClassForClass(Java.java:502)
at
org.jruby.javasupport.JavaSupport$3.computeValue(JavaSupport.java:154)
at
org.jruby.javasupport.JavaSupport$3.computeValue(JavaSupport.java:151)
at
org.jruby.util.collections.MapBasedClassValue.get(MapBasedClassValue.java:18)
at
org.jruby.javasupport.JavaSupport.getProxyClassFromCache(JavaSupport.java:207)
at org.jruby.javasupport.Java.getProxyClass(Java.java:450)
at org.jruby.javasupport.Java.getInstance(Java.java:389)
at org.jruby.javasupport.Java.getInstance(Java.java:371)
at
org.jruby.javasupport.JavaUtil.convertJavaToUsableRubyObject(JavaUtil.java:167)
at org.jruby.javasupport.JavaMethod.convertReturn(JavaMethod.java:517)
at
org.jruby.javasupport.JavaMethod.invokeDirectWithExceptionHandling(JavaMethod.java:441)
at org.jruby.javasupport.JavaMethod.invokeDirect(JavaMethod.java:304)
at
org.jruby.java.invokers.InstanceMethodInvoker.call(InstanceMethodInvoker.java:52)
at
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:134)
at org.jruby.ast.CallNoArgNode.interpret(CallNoArgNode.java:60)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.ast.DNode.appendToString(DNode.java:70)
at org.jruby.ast.DNode.buildDynamicString(DNode.java:88)
at org.jruby.ast.DNode.interpret(DNode.java:36)
at org.jruby.ast.CallOneArgNode.interpret(CallOneArgNode.java:57)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at org.jruby.ast.IfNode.interpret(IfNode.java:116)
at org.jruby.ast.NewlineNode.interpret(NewlineNode.java:105)
at
org.jruby.evaluator.ASTInterpreter.INTERPRET_METHOD(ASTInterpreter.java:74)
at
org.jruby.internal.runtime.methods.InterpretedMethod.call(InterpretedMethod.java:182)
at
org.jruby.internal.runtime.methods.DefaultMethod.call(DefaultMethod.java:186)
at
org.jruby.runtime.callsite.CachingCallSite.call(CachingCallSite.java:168)
at
rubyjit.GameMachine::GameActor$$onReceive_308BD95C280F55428DF2EEAF15AD2E7CAA298944316007184.file(/home/chris/game_machine/ruby/lib/game_machine/game_actor.rb:78)
at
rubyjit.GameMachine::GameActor$$onReceive_308BD95C280F55428DF2EEAF15AD2E7CAA298944316007184.file(/home/chris/game_machine/ruby/lib/game_machine/game_actor.rb)
at
rubyjit.GameMachine::GameActor$$onReceive_308BD95C280F55428DF2EEAF15AD2E7CAA298944316007184.file(/home/chris/game_machine/ruby/lib/game_machine/game_actor.rb)
at
org.jruby.internal.runtime.methods.JittedMethod.call(JittedMethod.java:121)
at
org.jruby.javasupport.proxy.JavaProxyConstructor$2.invoke(JavaProxyConstructor.java:224)
at org.jruby.proxy.akka.actor.UntypedActor$Proxy5.onReceive(Unknown
Source)
at
akka.actor.UntypedActor$$anonfun$receive$1.applyOrElse(UntypedActor.scala:163)
at akka.actor.ActorCell.receiveMessage(ActorCell.scala:498)
at akka.actor.ActorCell.invoke(ActorCell.scala:456)
at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:237)
at akka.dispatch.Mailbox.run(Mailbox.scala:219)
at
akka.dispatch.ForkJoinExecutorConfigurator$AkkaForkJoinTask.exec(AbstractDispatcher.scala:386)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:262)
at
scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:975)
at
scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1478)
at
scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:104)

No workaround I can think of, but we could modify JRuby to work around
this issue. We’ve already got some Scala hacks in place.

I don’t believe that this is really a Scala bug though. The reflection
API in getSimpleName is enforcing Java language specification rules on
all classes loaded by the JVM. The API should trust that the simple
name of the class is the name it reports minus the name of the
enclosing class it reports, rather than trying to enforce minor
idiosyncracies of inner class naming.

I’m preparing a patch for OpenJDK and will see if I can make the case.
On the other side…perhaps you can look into JRuby where we’re
calling getSimpleName and see if you can work around it?

  • Charlie