Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scala reflection: getDeclaringTrait?

When I research a new library, I sometimes find it hard to locate the implementation of a method.

In Java, Metho#getDeclaringClass provides the class that declared a given method. So by iterating over Class#getMethods, I can find for each method, the class that declared it.

In Scala, traits are converted to Java interfaces and a class that extends a trait will implement the methods of the trait by forwarding them to a companion class defining these methods statically. This means, that Method#getDeclaringClass will return the class, not the trait:

scala> trait A { def foo = {println("hi")}}
defined trait A

scala> class B extends A
defined class B

scala> classOf[B].getMethods.find(_.getName() == "foo").get.getDeclaringClass
res3: java.lang.Class[_] = class B

What is the best way to work around this? Meaning, given a class, how can I get a List[(Method, Class)] where each tuple is a method and the trait/class it was declared in?

like image 275
IttayD Avatar asked Dec 02 '09 15:12

IttayD


1 Answers

In Scala 2.8 you can use the ScalaSigParser to parse the scala specific byte code information.

This will be more stable than the byte code serialization format of scala traits, classes and methods.

import tools.scalap.scalax.rules.scalasig._
import scala.runtime._

val scalaSig = ScalaSigParser.parse(classOf[RichDouble]).get
val richDoubleSymbol = scalaSig.topLevelClasses.head
val methods = richDoubleSymbol.children filter ( _ match {
    case m : MethodSymbol => true
    case _ => false
})

methods foreach println
richDoubleSymbol.isTrait
ScalaSigParser.parse(classOf[Ordered[Any]]).get.topLevelClasses.head.isTrait

Prints:

scala> methods foreach println
MethodSymbol(x, owner=0, flags=20080004, info=23 ,None)
MethodSymbol(<init>, owner=0, flags=200, info=33 ,None)
[...]
MethodSymbol(isPosInfinity, owner=0, flags=200, info=117 ,None)
MethodSymbol(isNegInfinity, owner=0, flags=200, info=117 ,None)

scala> richDoubleSymbol.isTrait
res1: Boolean = false

scala> ScalaSigParser.parse(classOf[Ordered[Any]]).get.topLevelClasses.head.isTrait
res2: Boolean = true

I suppose following this road you can build a reflection API for Scala.

like image 194
Thomas Jung Avatar answered Oct 14 '22 00:10

Thomas Jung