【问题标题】:Finding objects using scala's runtime reflection使用 scala 的运行时反射查找对象
【发布时间】:2015-11-01 15:21:46
【问题描述】:

上下文

我目前使用 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]
}

如何找到对象并验证给定名称是否真的是对象? 也欢迎给定场景的替代方法。

【问题讨论】:

    标签: scala reflection


    【解决方案1】:

    对于第一个问题,您可以使用ClassUtil library。请注意,它会找到 Java 类,并且对应于 objects 的类将具有以 $class 结尾的名称。另见Scala Reflection - Loading or finding classes based on trait

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

    【讨论】:

    • 所以你建议只做反射并检查异常?
    • 第二个问题,是的。请参阅第一个编辑的答案。
    • 谢谢。我找到了一个类似的class path scanning 库并用于获取名称列表。关于对象,似乎没有适当的方法来确保它是 scala 对象,可能是因为 jvm 对 scala 没有特殊支持?无论如何,我会扫描所有具有该特征的类并仅使用模块。使用 scala 反映时,无论我使用 MyServiceFactory 还是 MyServiceFactory$ 似乎都指的是同一个对象实例,这也没有区别。
    • “似乎没有正确的方法来确保它是一个scala对象,可能是因为jvm没有对scala的特殊支持”正如答案中提到的,符号有一个isJava方法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    相关资源
    最近更新 更多