2012-08-13 60 views
3

我想以編程方式確定運行時的Scala類的所有屬性。例如,對於下面的Scala類,我想確定方法name1name3name4name5是干將爲A性質:如何在運行時確定一個Scala類的屬性?

class A(val name1: String, private val name2: String) { 
    val name3 = "" 
    var name4 = "" 
    def name5 = "" 
    def name6() = "" 
} 

大部分的工作可以用Java的反射API來完成。不幸的是,我無法檢測到name5name6()之間的差異。因此,我開始使用ScalaSigParser進行下一次試用,但不幸的是,ScalaSig的name5name6()的標誌也是相同的。這裏是我的代碼:

def gettersOf(clazz: Class[_]) = { 
    for (ssig <- ScalaSigParser.parse(clazz)) 
    yield { 
    ssig.symbols.toList.collect{ 
     case m: MethodSymbol => m 
    }.filter(m => (m.symbolInfo.flags & 0xFFFFF) == 0x200) 
    } 
} 

gettersOf(classOf[A]).get.foreach{m => 
    println(m.name + ": " + m) 
} 

正如你可以在下面的輸出這兩種方法的區別僅在於info值看:

name1: MethodSymbol(name1, owner=0, flags=28400200, info=22 ,None) 
<init>: MethodSymbol(<init>, owner=0, flags=200, info=38 ,None) 
name3: MethodSymbol(name3, owner=0, flags=8400200, info=45 ,None) 
name4: MethodSymbol(name4, owner=0, flags=8000200, info=45 ,None) 
name4_$eq: MethodSymbol(name4_$eq, owner=0, flags=8000200, info=54 ,None) 
name5: MethodSymbol(name5, owner=0, flags=200, info=45 ,None) 
name6: MethodSymbol(name6, owner=0, flags=200, info=66 ,None) 

然而,info似乎並不返回靜態常量。如果添加另一種方法類的name6info值就會產生變化,而似乎有一定的穩定性:

  • name3name4name5始終相同info
  • name6name5始終不同info values

是否有人知道info的含義以及如何使用它來確定它的確切類型?

相關問題:

+1

不是直接回答,但你知道,斯卡拉2。10即將到來,並有新的反思api?你可能會爲此嘗試一個里程碑。 – 2012-08-13 12:57:50

+0

@BrianSmith:謝謝你的提示。我實際上想立即跳到Scala 2.10。不幸的是,我的大部分依賴關係還不能用於2.10。 – 2012-08-13 13:08:20

回答

8

最好的辦法是使用即將推出的Scala 2.10的反射API。

下面是如何獲得2.10.0-M6一個類型的屬性:

scala> import reflect.runtime.universe._ 
import reflect.runtime.universe._ 

scala> typeOf[A].members.view.filter{_.isValue}.filter{!_.isMethod}.toList 
res0: List[reflect.runtime.universe.Symbol] = List(variable name4, value name3, value name2, value name1) 

遺憾的是沒有太多的閱讀材料上它。雖然有一些關於SO的回答問題。例如,this問題可能會對您有所幫助。另請參閱Daniel Sobral的博客文章this

+0

哇。這簡化了很多問題。一旦我所有的依賴庫與Scala 2.10兼容,我想我會繼續解決這個問題。 – 2012-08-13 14:07:01

+0

不幸的是,運行時反射會在多線程env下破壞。 – jilen 2014-05-05 10:52:48

0

我終於找到了解決辦法。而不是使用原始info值可以使用更多的信息infoType這似乎返回所有方法NullaryMethodType沒有括號:

def gettersOf(clazz: Class[_]) = { 
    for (ssig <- ScalaSigParser.parse(clazz)) 
    yield { 
    ssig.symbols.toList.collect { 
     case m: MethodSymbol => m 
    }.filter(m => (m.symbolInfo.flags & 0xFFFFF) == 0x200 && m.infoType.isInstanceOf[NullaryMethodType]) 
    } 
} 

在我們得到想要的結果,而不name6並沒有隱藏<init>方法結束:

name1: MethodSymbol(name1, owner=0, flags=28400200, info=22 ,None) 
name3: MethodSymbol(name3, owner=0, flags=8400200, info=45 ,None) 
name4: MethodSymbol(name4, owner=0, flags=8000200, info=45 ,None) 
name5: MethodSymbol(name5, owner=0, flags=200, info=45 ,None) 
3
import reflect.runtime.universe._ 
typeOf[A].members map (m => m -> m.typeSignature) collect { 
    case (m, nm: NullaryMethodType) => m 
} 
相關問題