Frage

I want to calculate the package name for a Scala class.

The code below works, but seems a bit verbose

def packagename(cls:ru.ClassSymbol):String = {
    def innerPackageName(cls:JavaUniverse#Symbol):List[JavaUniverse#Name] = {
      if(cls.owner != null && cls.owner.isPackage  ) {
         List(cls.name) ::: innerPackageName(cls.owner)
      }
      else {
          List(cls.name)
      }
    }
    val owner: JavaUniverse#Symbol = cls.owner
    innerPackageName(owner).filterNot{_.toString == "<root>"}.reverse.mkString(":")
  }

Is there a better way to do this?

War es hilfreich?

Lösung

The concept of traversing the owner chain until you hit a package (or, more precisely, a package class) is correct, however the code that you posted has minor stylistic issues. First, there's Symbol.fullName that concatenates the strings for you. Secondly, magic names necessary for public consumption of the reflection API are usually exposed somewhere in the API.

Here's how I would do what you're trying to do (change newTermName to TermName if you're on Scala 2.10.x):

00:08 ~/Projects/Master/sandbox (master)$ cat Test.scala
import scala.reflect.runtime.universe._
import scala.reflect.runtime.{currentMirror => cm}

object Test extends App {
  def packageName(sym: Symbol) = {
    def enclosingPackage(sym: Symbol): Symbol = {
      if (sym == NoSymbol) NoSymbol
      else if (sym.isPackage) sym
      else enclosingPackage(sym.owner)
    }
    val pkg = enclosingPackage(sym)
    if (pkg == cm.EmptyPackageClass) ""
    else pkg.fullName
  }
  println(packageName(typeOf[Test.type].member(TermName("packageName"))))
  println(packageName(cm.staticPackage("scala")))
  println(packageName(cm.staticClass("scala.collection.immutable.List")))
}

00:08 ~/Projects/Master/sandbox (master)$ sr

scala
scala.collection.immutable
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top