Dave
Dave

Reputation: 7699

Getting object instance by string name in scala

I need the object (or "singleton object" or "companion object"... anything but the class) defined by a string name. In other words, if I have:

package myPackage
object myObject

...then is there anything like this:

GetSingletonObjectByName("myPackage.myObject") match {
  case instance: myPackage.myObject => "instance is what I wanted"
}

Upvotes: 32

Views: 18574

Answers (5)

tuxSlayer
tuxSlayer

Reputation: 2824

Scala 2:

          val runtimeMirror = universe.runtimeMirror(this.getClass.getClassLoader)

          val objectClass = Class.forName("org.test.MyObject$")
          val moduleSymbol = runtimeMirror.staticModule(objectClass.getName)
          val moduleMirror = runtimeMirror.reflectModule(moduleSymbol)
          val instance = moduleMirror.instance

Or just use Java API to get the value from the static field:

          val instance = objectClass.getField("MODULE$").get(null)

Mind the $ in the object name.

Upvotes: 0

Nguyen Duc Dung
Nguyen Duc Dung

Reputation: 591

In scala 2.10 we can do like this

import scala.reflect.runtime.universe

val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)

val module = runtimeMirror.staticModule("package.ObjectName")

val obj = runtimeMirror.reflectModule(module)

println(obj.instance)

Upvotes: 57

psp
psp

Reputation: 12158

Adjustment to Thomas Jung's answer above: you would do better to say companion[List.type] because a) this should be a stable way to refer to it, not dependant on the name mangling scheme and b) you get the unerased types.

def singleton[T](implicit man: reflect.Manifest[T]) = {
  val name = man.erasure.getName()
  assert(name endsWith "$", "Not an object: " + name)
  val clazz = java.lang.Class.forName(name)

  clazz.getField("MODULE$").get(clazz).asInstanceOf[T]
}  

scala> singleton[List.type].make(3, "a")                       
res0: List[java.lang.String] = List(a, a, a)

Upvotes: 11

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297285

Barring reflection tricks, you can't. Note, for instance, how the method companion is defined on Scala 2.8 collections -- it is there so an instance of a class can get the companion object, which is otherwise not possible.

Upvotes: 1

Thomas Jung
Thomas Jung

Reputation: 33092

Scala is still missing a reflection API. You can get the an instance of the companion object by loading the companion object class:

import scala.reflect._
def companion[T](implicit man: Manifest[T]) : T = 
  man.erasure.getField("MODULE$").get(man.erasure).asInstanceOf[T]


scala> companion[List$].make(3, "s")
res0: List[Any] = List(s, s, s)

To get the untyped companion object you can use the class directly:

import scala.reflect.Manifest
def companionObj[T](implicit man: Manifest[T]) = { 
  val c = Class.forName(man.erasure.getName + "$")
  c.getField("MODULE$").get(c)
}


scala> companionObj[List[Int]].asInstanceOf[List$].make(3, "s")
res0: List[Any] = List(s, s, s)

This depends on the way scala is mapped to java classes.

Upvotes: 14

Related Questions