2013-07-05 5 views
7

스칼라 리플렉션 API (2.10)는로드 된 클래스를 검색하고 정의 된 특성을 구현하는 특정 클래스로 목록을 필터링하는 더 쉬운 방법을 제공합니까? 예;스칼라 리플렉션 - 특성을 기반으로 클래스로드 또는 찾기

trait Widget { 
    def turn(): Int 
} 

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

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

클래스 라이브러리에서 위젯을 확장하고 해당 클래스를 인스턴스화하는 모든 항목을 검색하려고합니다. 그래서 나는 CogSprocket의 인스턴스로 끝날 것입니다.

클래스 디렉토리를 반복하면서 자바 클래스를 반복하고 Class.forName을 사용하여 Class 객체를로드 한 다음 확인합니다. 스칼라 리플렉션 API가 검색하는 데 더 쉬운 방법을 제공하는지 궁금합니다. 지금까지 본 모든 예제는 항상 알려진 클래스에서 인스턴스화되고 사용 가능한 클래스를 검색하는 것이 아닙니다.

답변

13

이것은 ServiceLoader을위한 것입니다.

리플렉션 API를 사용하면 필요한 항목 (예 : 필터링은 물론 클래스 로더를 쿼리하지 않음)을 쉽게 분류 할 수 있다고 생각합니다.

"로드 된 클래스 검색"이란 실제로 이미로드 된 클래스를 의미합니다. 해당 클래스를 가져 오는 데는 this question을 참조하십시오.

당신이 알고있는 모든 위젯 클래스가로드되도록하는 이니셜 라이저가있는 위젯 라이브러리를 상상할 수 있습니다. 그런 다음 클라이언트는 이니셜 라이저 만 알아야합니다.

유형 테스트는 동일합니다. 당신이 형태 파라미터를 가지는 뭔가를 찾고있는

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 
} 

샘플 :

[email protected] is what I need 
[email protected] is not what I need, I'm looking for a widgets.Whatsit[widgets.Cog] 
당신이 ServiceLoader을 사용하고, 누가하지 않습니다 이후 10 년이 사건에

재 방문이 필요합니다.

[email protected]:~/tmp$ ls -R META-INF 
META-INF: 
MANIFEST.MF services 

META-INF/services: 
widgets.Whatsit widgets.Widget 
[email protected]:~/tmp$ cat META-INF/services/widgets.Widget 
widgets.Cog 
widgets.Sprocket 
[email protected]:~/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 
} 

스칼라와 자바 비교. getGenericInterfaces에 LOC를 몇 개 넣었는지 알기를 원했고 스칼라에서 원하는 것을 찾았지만 운동을 마쳤습니다.

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

프로그래머가 인터페이스를 서비스로 명시 적으로 선언하고 모든 구현을 'META-INF/services/...'에 나열해야 할 필요가 없습니까? – ghik

+0

예, 요점은 도서관에서 제공하는 내용을 알려주는 것입니다. 위젯을 위해 알려진 우주를 스캔하는 대신 알려진 위치에 주어진 클래스 로더를 쿼리 할 수있는 리소스가 있습니다. 나는 FYI 다른 조각을 붙였다. –

+0

우수! 고마워요! 그게 내가 필요한 것입니다. – Doswell