dimanche 9 août 2015

Finding objects using scala's runtime reflection

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.





Aucun commentaire:

Enregistrer un commentaire