0

I have a number of use cases for this, all around the idea of interop between existing Java libraries and new Scala Code. The use case I've selected is the easiest I think.

Use Case:

I working on providing a JUnit Runner for some scala tests (so that I can get my lovely red / green bar in Eclipse) The runner needs to have a constructor with a java class as a parameter. So in Scala I can do the following:

class MyRunner(val clazz: Class[Any]) extends Runner {
  def getDescription(): Description 
  def run(notifier: RunNotifier)
}

When I use either

@RunWith(MyRunner)
object MyTestObject 

or

@RunWith(MyRunner)
class MyTestClass

then the runner is indeed instantiated correctly, and is passed a suitable class object

Unfortunately what i want to do now is to "get hold of" the object MyTestObject, or create a MyTestClass, which are both Scala entities. I would prefer to use Scala Reflection, but I also want to use the standard Junit jar.

What I have done

The following Stackover flow questions were educational, but not the same problem. There were the nearest questions I could find

The discussion on Environments, Universes and Mirrors in http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html was good, and the similar documents on other scala reflection also helped. Mostly through it is about the Scala reflection.

I browsed the Scaladocs, but my knowledge of Scala reflection wasn't enough (yet) to let me get what I wanted out of them.

Edit: As asked here is the code of the class that is being created by reflection

@RunWith(classOf[MyRunner])
object Hello2 extends App {

  println("starting")

  val x= "xxx"
}

So the interesting thing is that the solution proposed below using the field called MODULE$ doesn't print anything and the value of x is null

Community
  • 1
  • 1
Stave Escura
  • 2,058
  • 1
  • 19
  • 24
  • I found that val instance = clazz.getField("MODULE$").get(null) works to get the object. It seems a little 'magical' is this the recommend way? – Stave Escura May 09 '13 at 11:03
  • This question is very good http://stackoverflow.com/questions/11020746/get-companion-object-instance-with-new-scala-reflection-api/11031443#11031443 – Stave Escura May 09 '13 at 11:34

1 Answers1

2

This solution works fine if you want to use plan old java reflection. Not sure if you can use scala reflection given all you will have is a Class[_] to work with:

object ReflectTest {
  import collection.JavaConversions._
  def main(args: Array[String]) {    
    val fooObj = instantiate(MyTestObject.getClass())
    println(fooObj.foo)
    val fooClass = instantiate(classOf[MyTestClass])
    println(fooClass.foo)
  }

  def instantiate(clazz:Class[_]):Foo = {
    val rm = ru.runtimeMirror(clazz.getClassLoader())
    val declaredFields = clazz.getDeclaredFields().toList
    val obj = declaredFields.find(field => field.getName() == "MODULE$") match{
      case Some(modField) => modField.get(clazz)
      case None => clazz.newInstance()
    }
    obj.asInstanceOf[Foo]
  }
}

trait Foo{
  def foo:String
}

object MyTestObject extends Foo{
  def foo = "bar"
}

class MyTestClass extends Foo{
  def foo = "baz"
}
cmbaxter
  • 35,283
  • 4
  • 86
  • 95
  • This works fine thank you. Now I have the instance, I suspect that I can use scala reflection from it rather than the class. – Stave Escura May 09 '13 at 12:18
  • Unfortunately while this works, it doesn't call the code that instantiates the fields in the companion object. For example if I have val x=1 inside the companion object, java reflection on the instance created returns null. – Stave Escura May 09 '13 at 12:31
  • Can you provide the structure of the two classes you mention here in your question so I can provide a solution? Is this the class based example or the object based example? Just want to see the class/companion relationship and what you want to happen so I can provide an answer. – cmbaxter May 09 '13 at 12:35
  • I've updated the original post with the code of the class at the end. Thank you for the feedback and help – Stave Escura May 09 '13 at 12:52
  • 1
    Try taking `extends App` off of your `object`. – cmbaxter May 09 '13 at 12:55
  • Wow. Just wow. That worked. Now I just have to wonder why that worked. Talk about magic. Thank you for all the help – Stave Escura May 09 '13 at 12:59
  • I'm not sure what the deal with `App` is in regards to reflection. I generally stay away from `App`. – cmbaxter May 09 '13 at 13:02