Lucas Lima
Lucas Lima

Reputation: 902

How to get the declaring class / trait using Scala reflection?

Using Java reflection, I can make:

MyObject
  .getClass
  .getMethods
  .map(_.getDeclaringClass())

For each method declared in the Object MyObject, I will get the declaring class of that method / value - what I'm interest here is, specifically, in telling whether those methods / values are being declared by MyObject or not.

That said, I don't want to use Java reflection (because, among other things, I lose Scala features in the process - for instance, getMethods will return both methods and values, because the way values are represented in Java). How can I achieve the same with Scala reflection? This is what I've got so far:

val ru = scala.reflect.runtime.universe
val currentMirror = scala.reflect.runtime.currentMirror
val instanceMirror = currentMirror.reflect(MyObject)
val moduleSymbol = currentMirror.moduleSymbol(MyObject.getClass)

val methodSymbols =  moduleSymbol
  .info
  .members
  .map(_.asMethod)

methodSymbols
  .map(_.getDeclaringClassInScala) // ???????

Of course, the last line won't work. I tried to browse the docs, to no avail. Any help appreciated.

EDIT: just to clarify, the question has been written in a more generic way in order to help more people. My use case, in particular, is filtering all the methods that have been declared directly by MyObject, instead of inherited by whatever other module or class.

Upvotes: 1

Views: 657

Answers (2)

Dmytro Mitin
Dmytro Mitin

Reputation: 51703

My use case, in particular, is filtering all the methods that have been declared directly by MyObject, instead of inherited by whatever other module or class.

Then it's just enough to use .decls instead of .members

trait MyTrait1 {
  def bar(): Unit = println("bar")
}
trait MyClass {
  def baz(): Unit = println("baz")
}

object MyObject extends MyClass with MyTrait1 {
  def foo(): Unit = println("foo")
}

typeOf[MyObject.type].members.filter(_.isMethod).toList
// List(method foo, constructor MyObject, method bar, method $init$, method baz, method synchronized, method ##, method !=, method ==, method ne, method eq, method notifyAll, method notify, method clone, method getClass, method hashCode, method toString, method equals, method wait, method wait, method wait, method finalize, method asInstanceOf, method isInstanceOf)
typeOf[MyObject.type].decls.filter(_.isMethod).toList
// List(constructor MyObject, method foo)

So I guess there is no need in methodSymbols.map(_.owner.asClass).filter(_ == currentMirror.symbolOf(MyObject)) (I guess you meant symbolOf[MyObject.type]).

MyObject can't inherit methods from other modules (objects), only from classes (traits).

Upvotes: 1

user
user

Reputation: 7604

The owner method should help you here. It'll return the enclosing class.

methodSymbols.map(_.owner.asType)

Example in Scastie

Upvotes: 1

Related Questions