如何从 sbt 中发现定义 class 的库?
How to discover the library that defines a class from sbt?
例如,我想发现定义的 class 路径中的哪个库声明了 class,如 ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP ?
任何体面的 IDE 都提供了一个功能,您可以在其中搜索此类类型(在 Eclipse 中查找类型),但是如何在 SBT 中完成此操作?有什么 task/command/plugin 可以帮我解决这个问题吗?
这样的功能对于 class 冲突检测也很有用(如果多个 jar 将定义相同的 class):请参阅此相关问题 How can I find duplicate classes amongst dependencies with SBT。
我以为我知道的技术实际上并不奏效。
正在进行分析(无效)
core> consoleProject
[info] Starting scala interpreter...
scala> val a = (compile in Compile).eval
a: sbt.inc.Analysis = Analysis: 69 Scala sources, 1092 classes, 2 external source dependencies, 4 binary dependencies
scala> val stamps = a.stamps
stamps: sbt.inc.Stamps = Stamps for: 1092 products, 69 sources, 4 binaries, 4 classNames
scala> val classNames = stamps.classNames
classNames: Map[java.io.File,String] = Map(/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/rt.jar -> java.lang.Object, /Users/eugene/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.6.jar -> scala.Function1, /Users/eugene/.ivy2/cache/org.typelevel/machinist_2.11/jars/machinist_2.11-0.3.0.jar -> machinist.Ops, /Users/eugene/.ivy2/local/org.spire-math/algebra_2.11/0.2.0-SNAPSHOT/jars/algebra_2.11.jar -> algebra.Eq)
这个乍一看好像有用,但是Map的方向是从File
到String
,所以其实用处不大。
Java反射
如果你能找到 Class
,你可以这样做:
scala> a.getClass.getClassLoader match { case ucl: java.net.URLClassLoader => ucl.getResource(a.getClass.getName.replace('.', '/') + ".class") }
res13: java.net.URL = jar:file:/Users/eugene/.conscript/boot/scala-2.10.5/org.scala-sbt/sbt/0.13.9-RC1/incremental-compiler-0.13.9-RC1.jar!/sbt/inc/MAnalysis.class
例如,我想发现定义的 class 路径中的哪个库声明了 class,如 ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP ?
任何体面的 IDE 都提供了一个功能,您可以在其中搜索此类类型(在 Eclipse 中查找类型),但是如何在 SBT 中完成此操作?有什么 task/command/plugin 可以帮我解决这个问题吗?
这样的功能对于 class 冲突检测也很有用(如果多个 jar 将定义相同的 class):请参阅此相关问题 How can I find duplicate classes amongst dependencies with SBT。
我以为我知道的技术实际上并不奏效。
正在进行分析(无效)
core> consoleProject
[info] Starting scala interpreter...
scala> val a = (compile in Compile).eval
a: sbt.inc.Analysis = Analysis: 69 Scala sources, 1092 classes, 2 external source dependencies, 4 binary dependencies
scala> val stamps = a.stamps
stamps: sbt.inc.Stamps = Stamps for: 1092 products, 69 sources, 4 binaries, 4 classNames
scala> val classNames = stamps.classNames
classNames: Map[java.io.File,String] = Map(/Library/Java/JavaVirtualMachines/jdk1.7.0_79.jdk/Contents/Home/jre/lib/rt.jar -> java.lang.Object, /Users/eugene/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.6.jar -> scala.Function1, /Users/eugene/.ivy2/cache/org.typelevel/machinist_2.11/jars/machinist_2.11-0.3.0.jar -> machinist.Ops, /Users/eugene/.ivy2/local/org.spire-math/algebra_2.11/0.2.0-SNAPSHOT/jars/algebra_2.11.jar -> algebra.Eq)
这个乍一看好像有用,但是Map的方向是从File
到String
,所以其实用处不大。
Java反射
如果你能找到 Class
,你可以这样做:
scala> a.getClass.getClassLoader match { case ucl: java.net.URLClassLoader => ucl.getResource(a.getClass.getName.replace('.', '/') + ".class") }
res13: java.net.URL = jar:file:/Users/eugene/.conscript/boot/scala-2.10.5/org.scala-sbt/sbt/0.13.9-RC1/incremental-compiler-0.13.9-RC1.jar!/sbt/inc/MAnalysis.class