使用 scala 的运行时反射查找对象
Finding objects using scala's runtime reflection
上下文
我目前使用 scala 2.11.6,将来可能使用 2.11.7。
给定 class 路径中已编译的 class 文件,我想做两件事:
查找实现特定接口的任何对象的名称:
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()
问题
这两种情况的问题是验证类型继承和确保它是一个单例对象。
检查 class 似乎很简单,但考虑到所有 documentation
我能理解,none 帮助我实现了类似 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 library. Note that it'll find Java classes, and the ones which correspond to object
s will have names ending in $class
. See also Scala Reflection - Loading or finding classes based on trait。
对于第二个,object
s are called "modules" 在 Scala 反射中,所以你不需要 isSingletonObject(name)
;如果不是,您代码中的 rm.staticModule(name).asModule
将失败。似乎没有办法检查它是否是编译器生成的空伴生对象(isSynthetic
returns false),但无论如何它们都会被子类型检查排除(静态也是如此) Java 类 的部分内容,但您也可以使用 isJava
).
过滤掉这些内容
上下文
我目前使用 scala 2.11.6,将来可能使用 2.11.7。 给定 class 路径中已编译的 class 文件,我想做两件事:
查找实现特定接口的任何对象的名称:
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()
问题
这两种情况的问题是验证类型继承和确保它是一个单例对象。
检查 class 似乎很简单,但考虑到所有 documentation
我能理解,none 帮助我实现了类似 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 library. Note that it'll find Java classes, and the ones which correspond to object
s will have names ending in $class
. See also Scala Reflection - Loading or finding classes based on trait。
对于第二个,object
s are called "modules" 在 Scala 反射中,所以你不需要 isSingletonObject(name)
;如果不是,您代码中的 rm.staticModule(name).asModule
将失败。似乎没有办法检查它是否是编译器生成的空伴生对象(isSynthetic
returns false),但无论如何它们都会被子类型检查排除(静态也是如此) Java 类 的部分内容,但您也可以使用 isJava
).