Get all the classes that implements a trait in Sca

2019-01-23 18:42发布

I want to list out all the case classes which implements a particular trait. I am currently using Clapper ClassUtil for doing that. I am able to get the case classes that are directly implementing a trait. However, I am not able to get the other classes which are not directly implementing the trait. How can I get all classes which directly or indirectly implements a trait. ?

val finder = ClassFinder()
finder.getClasses().filter(_.isConcrete).filter(_.implements("com.myapp.MyTrait"))

Scala Version : 2.11

Clapper Class Util Version : 1.0.6

Is there any other way I can get these information? Can someone point me to the right direction? I tried using scala.reflect but could not understand how to get the info.

EDIT:

Sample traits and usages:

trait BaseEntity
trait NamedEntity{ val name:String}
trait MasterDataEntity extends NamedEntity

case class Department(id:Long, override val name:String) extends MasterDataEntity
case class Employee(id:Long, name:String) extends BaseEntity
case class User(id:Long, override val name:String) extends NamedEntity

Now, if I give the trait as NamedEntity, I should be able to get both Department and User since they both are directly or indirectly implementing NamedEntity. With implements method, it will give only User. I also tried by using interfaces method, which will also provide the direct super classes only.

2条回答
ら.Afraid
2楼-- · 2019-01-23 19:19

ClassUtil now contains this functionality (v1.4.0, maybe also in earlier versions):

val finder = ClassFinder()
val impl = ClassFinder.concreteSubclasses("foo.NamedEntity", finder.getClasses())
查看更多
等我变得足够好
3楼-- · 2019-01-23 19:21

Looking at the source code, the problem seems to be that it doesn't follow the interfaces hierarchy. If you do that, you find all instances:

package foo

import java.io.File

import org.clapper.classutil.{ClassFinder, ClassInfo}

object Main extends App {
  val jar     = new File("target/scala-2.11/class_test_2.11-0.1.0.jar")
  val finder  = ClassFinder(jar :: Nil)
  val classes = ClassFinder.classInfoMap(finder.getClasses().iterator)
  val impl    = find("foo.NamedEntity", classes)
  impl.foreach(println)

  def find(ancestor: String, classes: Map[String, ClassInfo]): List[ClassInfo] =
    classes.get(ancestor).fold(List.empty[ClassInfo]) { ancestorInfo =>
      val ancestorName = ancestorInfo.name

      def compare(info: ClassInfo): Boolean =
        info.name == ancestorName ||
        (info.superClassName :: info.interfaces).exists {
          n => classes.get(n).exists(compare)
        }

      val it = classes.valuesIterator
      it.filter { info => info.isConcrete && compare(info) } .toList
    }
}
查看更多
登录 后发表回答