mercredi 31 juillet 2019

Some package classes of classpath can not be found when I want to trace a Package symbol and inspect a class or object

There is such a premise.

organization: "com.xxx"

project A
  com.xxx.a.aa
  com.xxx.a.mm
project B dependsOn A
  com.xxx.b.bb
  com.xxx.b.nn
  com.xxx.b.runtime
    Extractor.scala
project C dependsOn B
  com.xxx.c.cc
  com.xxx.c.oo
  com.xxx.c
    Main.scala

Extractor.scala loads the classpath under the package _root_ and tries type checking.

def run(): Vector[universe.Symbol] = {
    recursivePackageExplore(
      Vector(rootPackage)
    )
  }

  private final def rootPackage: universe.Symbol = universe.runtimeMirror(getClass.getClassLoader).RootPackage.info.typeSymbol

  @tailrec
  private final def recursivePackageExplore(selfPackages: Vector[universe.Symbol],
                                            result: Vector[universe.Symbol] = Vector.empty): Vector[universe.Symbol] = {
    selfPackages match {
      case x if x.isEmpty => result
      case _              =>
        val (packages, modules) = selfPackages.flatMap(_.typeSignature.members).distinct.collect {
          case x if selfPackages.contains(x) =>
            None -> None
          case x if x.isPackage                                                         =>
            Some(x) -> None
          case x if x.isModule && !x.toString.startsWith("package object") && !x.isAbstract                                         =>
            None -> Some(x)
        } match {
          case x => x.flatMap(_._1) -> x.flatMap(_._2)
        }

        recursivePackageExplore(
          packages,
          result ++ recursiveModuleExplore(modules)
        )
    }
  }

  @tailrec
  private final def recursiveModuleExplore(n: Vector[universe.Symbol],
                                           result: Vector[universe.Symbol] = Vector.empty): Vector[universe.Symbol] = {
    n match {
      case accessibleSymbol if accessibleSymbol.isEmpty => result
      case accessibleSymbol                             =>
        recursiveModuleExplore(
          accessibleSymbol.withFilter(_.isModule).flatMap(_.typeSignature.members).collect {
            case x if x.isModule => x
          },
          result ++ accessibleSymbol.filter(_.accepted))
    }
  }

When I ran the Extractor from Main, I expected that most classes under project A, B and C would be returned in result. However, it seems that only classes of some packages under project B could actually be detected.

This works as expected if you set the run function to macro. In the case of runtime reflection, Symbol(package).typeSignature.members was considered to load the classpath. Did I make a mistake?





Aucun commentaire:

Enregistrer un commentaire