使用scala的运行时反射查找对象

时间:2015-08-09 18:02:07

标签: scala reflection

上下文

我目前使用scala 2.11.6,将来可能使用2.11.7。 鉴于类路径中已编译的类文件,我想做两件事:

  • 查找实现特定接口的任何对象的名称:

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

    这里的名称类似于my.package.MyServiceFactory,因为它实现了ServiceFactory特征。

  • 给定对象的完全限定名称,我想获得对象实例的引用。

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

问题

两种情况的问题是验证类型继承,确保它是单例对象。 检查班级似乎是直截了当的,但考虑到所有documentation 我理解,没有人帮我实现像isSingletonObject(name: String): Boolean这样的东西:

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]
}

如何找到对象并验证给定名称是否真的是一个对象? 对于给定方案的替代方法也是受欢迎的。

1 个答案:

答案 0 :(得分:0)

对于第一个问题,您可以使用ClassUtil library。请注意,它将查找Java类,与object对应的名称将以$class结尾。另请参阅Scala Reflection - Loading or finding classes based on trait

对于Scala反射中的第二个object s are called "modules",您不需要isSingletonObject(name);如果不是,代码中的rm.staticModule(name).asModule将失败。似乎没有办法检查它是否是编译器生成的空伴随对象(isSynthetic返回false),但是无论如何它们都将被子类型检查排除(所以Java类的静态部分,但您也可以使用isJava)过滤掉它们。