2

Context

I use scala 2.11.6 currently, possibly 2.11.7 in the future. Given compiled class files in the classpath, I want to do 2 things:

  • Find the name of any objects that implements a certain interface:

    trait Service
    trait ServiceFactory {
      def create(): Service
    }
    ...
    package my.package
    object MyServiceFactory extends ServiceFactory {
      def create(): Service = new Service()
    }
    

    Here the name would be something like my.package.MyServiceFactory as it implements the ServiceFactory trait.

  • Given the fully qualified name of the object I want to get the reference to the object's instance.

    val factory = getInstance[ServiceFactory]("my.package.MyServiceFactory")
    val service = factory.create()
    

Problem

The problem to both scenarios is verifying the type inheritance and making sure it is a singleton object. Checking the class seems straight-forward but given all the documentation I could understand, none helped me implementing something like isSingletonObject(name: String): Boolean as used in:

import scala.reflect.runtime.{universe => ru}
val rm = ru.runtimeMirror(classLoader)

def getInstance[T](name: String)(implicit tt: ru.TypeTag[T]): T = {
  if (!isSingletonObject(name)) throw new RuntimeException(
    s"$name does not specify a singleton object")
  val moduleSym = try rm.staticModule(name).asModule
  if (!(moduleSym.moduleClass.asClass.selfType <:< tt.tpe))
      throw new RuntimeException("Type of loaded module " + moduleSym.fullName
        + " does not satisfy subtype relationship with "
        + tt.tpe.typeSymbol.fullName)
  val mm = rm.reflectModule(moduleSym.asModule)
  mm.instance.asInstanceOf[T]
}

How can one find objects and verify that a given name is really an object? Alternative approaches to the given scenarios are also welcome.

Araeos
  • 171
  • 2
  • 9

1 Answers1

0

For the first question, you could use ClassUtil library. Note that it'll find Java classes, and the ones which correspond to objects will have names ending in $class. See also Scala Reflection - Loading or finding classes based on trait.

For the second, objects are called "modules" in Scala reflection, so you don't need isSingletonObject(name); if it isn't, rm.staticModule(name).asModule in your code will fail. There doesn't seem to be a way to check if it's a compiler-generated empty companion object (isSynthetic returns false), but they will be ruled out by the subtyping check anyway (so will the static parts of Java classes, but you can also filter those out using isJava).

Community
  • 1
  • 1
Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • So you suggest to just do the reflection and check for exceptions? – Araeos Aug 10 '15 at 13:45
  • For the second question, yes. See the edited answer for the first. – Alexey Romanov Aug 10 '15 at 14:54
  • Thanks. I found a similiar [class path scanning](https://code.google.com/p/reflections/) library and use to get a list of names. Concerning the objects, it seems there is no proper way to make sure it is a scala object, maybe because jvm has no special support for scala? Anyway I scan for all classes that have the trait and use only the modules.It also makes no difference whether I use `MyServiceFactory` or `MyServiceFactory$` both refer seemingly to the same object instance when reflected using scala. – Araeos Aug 10 '15 at 23:20
  • "it seems there is no proper way to make sure it is a scala object, maybe because jvm has no special support for scala" As mentioned in the answer, symbols have an `isJava` method. – Alexey Romanov Aug 11 '15 at 06:57