如何在运行时确定Scala类的属性?

时间:2012-08-13 12:13:15

标签: scala reflection runtime introspection

我想在运行时以编程方式确定Scala类的所有属性。例如,对于以下Scala类,我想确定方法name1name3name4name5A属性的getter :

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

大部分工作都可以使用Java的反射API完成。很遗憾,我无法检测name5name6()之间的区别。因此,我使用ScalaSigParser开始了下一次试用,但不幸的是,name5name6()的ScalaSig标志也是一样的。这是我的代码:

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似乎没有返回静态常量。如果您在课程中添加其他方法,则info的{​​{1}}值会发生变化,但似乎有一些稳定性:

  • name6name3name4始终具有相同的name5
  • infoname6始终有不同的name5

有人知道info的含义以及如何使用它来确定它是哪种方法?

相关问题:

3 个答案:

答案 0 :(得分: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)

不幸的是,它的阅读材料还不多。尽管如此,有一些已回答的问题。例如,您可能会对this问题感兴趣。另请查看Daniel Sobral撰写的this博文。

答案 1 :(得分:3)

import reflect.runtime.universe._
typeOf[A].members map (m => m -> m.typeSignature) collect { 
  case (m, nm: NullaryMethodType) => m 
}

答案 2 :(得分: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)