上下文
我目前使用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()
问题
这两种情况的问题都是验证类型继承和确保它是一个singleton对象。检查类似乎很简单,但提供了所有文档我可以理解,没有人帮助我实现类似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]
}
如何找到对象并验证给定的名称是否真的是对象?也欢迎对给定情景采取替代方法。
对于第一个问题,您可以使用ClassUtil库。请注意,它会找到Java类,与object
对应的类的名称将以$class
结尾。另请参阅Scala反射-基于trait加载或查找类。
第二,object
在Scala反射中被称为"模块",因此您不需要isSingletonObject(name)
;否则,代码中的rm.staticModule(name).asModule
将失败。似乎没有办法检查它是否是编译器生成的空伴随对象(isSynthetic
返回false(,但它们无论如何都会被子类型检查排除在外(Java类的静态部分也是如此,但您也可以使用isJava
过滤掉它们(。