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}"
}
}