Search code examples
scalareflectionsingletoncompanion-object

How to access a Scala object instance given it's full qualified name?


So I have defined a Scala object using the following code:

trait SomeTrait {
  def someMethod(): Unit
}

package somepackage1 {
  object Impl1 extends SomeTrait {
    def someMethod(): Unit = { }
  }
  object Impl2 extends SomeTrait {
    def someMethod(): Unit = { }
  }
}

I want to access the object given its fully qualified name i.e. somepackage1.Impl2. A method something like following:

package object somewhereElse {
  def getImpl(qualifiedName: String): SomeTrait = {
    ???
  }
}

What should be the code as part of getImpl method?


Solution

  • Here is a solution that uses the Java Reflection API (you might want to use the newer Scala Reflection API instead):

    trait SomeTrait {
      def someMethod(): Unit
    }
    
    package somepackage1 {
      object Impl1 extends SomeTrait {
        def someMethod(): Unit = { println("impl 1") }
      }
      object Impl2 extends SomeTrait {
        def someMethod(): Unit = { println("impl 2") }
      }
    }
    
    package object somewhereElse {
      def getImpl(qualifiedName: String): SomeTrait = {
        val clazz = Class.forName(qualifiedName + "$")
        clazz
          .getField("MODULE$")
          .get(clazz)
          .asInstanceOf[SomeTrait]
      }
    }
    
    object Demo {
      def main(args: Array[String]): Unit = {
        somewhereElse.getImpl("somepackage1.Impl2").someMethod()
      }
    }
    

    It's quite similar to Dima's comment above, with two minor differences: note the '$' appended to class name, and also the .get(clazz) instead of just .get() (without the clazz, it throws java.lang.NoSuchFieldException: MODULE$).

    When saved to file f.scala, and compiled and invoked using

    scalac f.scala && scala Demo
    

    it prints:

    impl 2