Getting object instance by string name in scala

16,265

Solution 1

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.

Solution 2

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)

Solution 3

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)

Solution 4

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.

Share:
16,265
Dave
Author by

Dave

Updated on July 12, 2022

Comments

  • Dave
    Dave almost 2 years

    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"
    }
    
  • Thomas Jung
    Thomas Jung over 14 years
    Could you add a link to the source, please?
  • Daniel C. Sobral
    Daniel C. Sobral over 14 years
    lampsvn.epfl.ch/trac/scala/browser/scala/trunk/src/library/…‌​, though, hopefully, 2.8's Scaladoc 2 will soon contain links to the source, as already happens with 2.7.
  • Dave
    Dave over 14 years
    Holy cow. Do you know if this syntax is a fixed part of the Scala spec (as fixed as anything else in the language, anyway)? It seems like a bad idea to rely on this. And since my goal was to make the code clearer... Thank you!
  • IttayD
    IttayD over 13 years
    How is this better than just List.make(3, "a")? The OP wanted to get the object by string name
  • pdinklag
    pdinklag about 13 years
    As he mentioned, there is no reflection API in Scala yet, so whether this is covered by the Scala spec or not, this is the only way for you to do it. I noticed this question / answer is over a year old, are there any news here?
  • appbootup
    appbootup almost 13 years
    Thanks! This is exactly what I was looking for. It's certainly a hack, but less dirty than what I managed to come up with.