使用Scala和反射列出包中的类数组

时间:2017-03-20 18:02:50

标签: scala reflection

请注意:此问题是关于如何在 Scala 中完成类路径扫描(通过反射),而不是Java。我在这个网站上的任何地方都没有看到这个问题,因此我不相信这是一个重复的问题。

我有一个Scala项目目录结构,如下所示:

myapp/
  src/main/scala/
    com/
      me/
        myapp/
          messages/
            BaseMessage.scala
            FizzMessage.scala
          utils
            <omitted for brevity>
          logging
            <omitted for brevity>
          driver
            <omitted for brevity>

注意messages包。目前它只在其中定义了两个类,BaseMessage(抽象基类)和FizzMessage(扩展BaseMessage)。但最终它将包含数百个其他所有BaseMessage子类的类。

在我的代码中,我有以下内容:

deviceManager.registerMessage(new FizzMessage())

随着时间的推移,我向BaseMessage包中添加了数十个,可能是数百个messages子类,我将不得不添加一行代码来注册&#34;注册&#34;每种新的消息类型。随后,如果我重构或删除消息,我将不得不记得从上面删除他们各自的注册码。这将很难管理,我想知道我是否可以使用反射来扫描messages包裹中的BaseMessage impls,然后注册它们:

val messageImpls : Array[T > BaseMessage] = getViaReflection("com.me.myapp.messages")
messageImpls.foreach { msgImpl =>
  deviceManager.registerMessage(msgImpl)
}

关于如何实现这一目标的任何想法?

1 个答案:

答案 0 :(得分:0)

如果您可以使用getResources访问感兴趣的类,则可以过滤这些结果,甚至递归子目录(此处未显示):

def getClasses(packageName: String) = {
    val classLoader = getClass.getClassLoader
    val path = packageName.replace('.', '/')
    val resources: util.Enumeration[URL] = classLoader.getResources(path)

    Iterator.continually((resources, resources.nextElement))
      .takeWhile(_._1.hasMoreElements)
      .map{ case (_, resource: URL) =>
        new File(resource.getFile)
          .listFiles
          .withFilter(_.getName.endsWith(".class"))
          .map{ file =>
            Class.forName(packageName + '.' + file.getName.dropRight(6))
          }
      }
  }