Scala Reflection-загрузка или поиск классов на основе признака

предоставляет ли API отражения scala (2.10) какие-либо более простые средства поиска загруженных классов и фильтрации списка для определенных классов, которые реализуют определенный признак? ie;

trait Widget {
  def turn(): Int
}

class Cog extends Widget {
  def turn() = {
    5
  }
}

class Sprocket extends Widget {
  def turn() = {
   10
  }
}

Я хочу найти в библиотеке классов все, что расширяет виджет и создает экземпляры этих классов. Таким образом, я бы закончил с экземпляром Cog и Sprocket.

Я сделал подобное в Java, повторяя каталоги классов, формируя имена классов и используя Класс.forName для загрузки объекта класса, чтобы затем проверить. Мне просто интересно, дает ли API отражения scala более простой способ поиска. Все примеры, которые я видел до сих пор, всегда начинались с экземпляра известного класса, а не с поиска доступных классов.

1 ответов


это ServiceLoader для.

Я думаю, что API отражения упрощает сортировку того, что вам нужно (т. е. для фильтрации, но не для запроса загрузчика классов).

если, по вашей фразе, "поиск в загруженных классов", вы действительно имеете в виду классы, которые уже загружены, см. этот вопрос для их получения.

вы можете себе представить библиотеку виджетов с инициализатором, который просто гарантирует, что все классы виджетов он знает о загружаются. Тогда клиент должен знать только инициализатор.

тип теста тот же.

val need = typeOf[Whatsit[Cog]]
for (x <- (ServiceLoader load classOf[Whatsit[_]]).asScala) { 
  val im = currentMirror reflect x 
  if (im.symbol.toType weak_<:< need)
    Console println s"$x is what I need"
  else
    Console println s"$x is not what I need, I'm looking for a $need"
} 

где вы ищете что-то с параметрами типа:

trait Whatsit[+A <: Widget] {
  def widget: A
}

class Engine extends Whatsit[Cog] {
  def widget = new Cog
}

class FlyWheel extends Whatsit[Sprocket] {
  def widget = new Sprocket
}

пример:

widgets.Engine@f9da0cd is what I need
widgets.FlyWheel@4cfdbb9f is not what I need, I'm looking for a widgets.Whatsit[widgets.Cog]

на случай, если прошло десять лет с тех пор, как вы использовали ServiceLoader, и кто не нуждается в обновлении:

apm@mara:~/tmp$ ls -R META-INF
META-INF:
MANIFEST.MF  services

META-INF/services:
widgets.Whatsit  widgets.Widget
apm@mara:~/tmp$ cat META-INF/services/widgets.Widget
widgets.Cog
widgets.Sprocket
apm@mara:~/tmp$ cat META-INF/services/widgets.Whatsit 
widgets.Engine
widgets.FlyWheel

материал:

package widgets

trait Widget {
  def turn(): Int
  override def toString = s"Widget ${getClass.getSimpleName}"
}

class Cog extends Widget {
  def turn() = 5
}

class Sprocket extends Widget {
  def turn() = 10
}

trait Whatsit[+A <: Widget] {
  def widget: A
  override def toString = s"Whatsit ${getClass.getSimpleName} of $widget"
}

class Engine extends Whatsit[Cog] {
  def widget = new Cog
}

class FlyWheel extends Whatsit[Sprocket] {
  def widget = new Sprocket
}

сравнение Scala и Java. Я собирался получить представление о том, сколько LOC to getGenericInterfaces и найдите то, что вы хотите в Scala, но тогда я положу конец упражнениям.

package findwidgets

import reflect._
import reflect.runtime.universe._
import reflect.runtime.currentMirror
import scala.collection.JavaConverters._
import java.util.ServiceLoader

object Test extends App {
  import widgets.{ Widget, Whatsit, Cog }
  val ws = (ServiceLoader load classOf[Widget]).asScala
  for (w <- ws) {
    Console println s"Turn a ${w.getClass} by ${w.turn}"
  }
  val need = typeOf[Whatsit[Cog]]
  for (x <- (ServiceLoader load classOf[Whatsit[Cog]]).asScala) {
    val im = currentMirror reflect x
    if (im.symbol.toType weak_<:< need)
      Console println s"$x is what I need"
    else
      Console println s"$x is not what I need, I'm looking for a $need"
    // java says:
    if (classOf[Whatsit[Cog]] isAssignableFrom x.getClass)
      Console println s"Um, OK, I'll take the $x"
    else
      Console println s"${classOf[Whatsit[Cog]]} isn't ass'able from ${x.getClass}"
  }
}