IntelliJ Scala插件获取声明依赖及依赖树的技术求助
针对IntelliJ SBT依赖分析插件的两个技术问题解决方案
问题1:获取项目所有声明依赖并支持跳转
你之前依赖SbtDependencyModifier.scala的方法覆盖场景有限,建议改用IntelliJ Scala插件提供的SbtProjectData与SbtModule相关API来覆盖多场景:
- 遍历全项目模块:通过
SbtUtil.getSbtProjects(project)获取所有SbtProject实例,再递归遍历每个项目的子模块 - 提取全配置依赖:针对每个SbtModule,调用
module.getResolvedScopedDependencies()获取包含compile、test、runtime、provided等所有配置维度的声明依赖;同时可通过module.getSbtProjectData().getLibraryDependencies()拿到原始声明的依赖坐标 - 实现跳转逻辑:拿到依赖坐标后,通过
LibraryTable.getInstance(project)匹配对应Library实例,再用library.getFiles(OrderRootType.CLASSES)获取类文件根路径,最后借助NavigationService.getInstance().navigate()实现跳转到对应类或资源;若需跳转源码,替换为OrderRootType.SOURCES定位源码文件
示例代码片段:
import com.intellij.openapi.project.Project import com.intellij.openapi.roots.libraries.LibraryTable import org.jetbrains.sbt.project.data.SbtProjectData import org.jetbrains.sbt.util.SbtUtil def getAllDeclaredDependencies(project: Project): Seq[(String, String, String)] = { SbtUtil.getSbtProjects(project).flatMap { sbtProject => sbtProject.getModules.flatMap { module => module.getSbtProjectData().getLibraryDependencies.map { dep => (dep.organization, dep.name, dep.revision) } } } } // 跳转实现示例 def navigateToDependency(project: Project, org: String, name: String, rev: String): Unit = { LibraryTable.getInstance(project).getLibraries.find { lib => lib.getName.contains(s"$org:$name:$rev") }.foreach { lib => lib.getFiles(com.intellij.openapi.roots.OrderRootType.CLASSES).headOption.foreach { classRoot => // 可根据具体类名进一步定位到目标文件,此处省略类名匹配逻辑 val navigationItem = // 构建对应NavigationItem实例 com.intellij.openapi.navigation.NavigationService.getInstance().navigate(navigationItem, true) } } }
需额外处理sbt的动态版本依赖(如通过变量声明的版本号)和子项目依赖,可通过module.getModuleDependencies()获取项目间依赖关系并递归处理。
问题2:直接获取依赖树/图
无需依赖sbt-dependency-graph插件与shell命令,可通过两种方式实现:
- 复用IntelliJ缓存的解析后依赖数据:
IntelliJ Scala插件同步sbt项目时会缓存已解析依赖的层级关系,通过SbtDependencyService可直接读取。示例:import org.jetbrains.sbt.services.SbtDependencyService import org.jetbrains.sbt.util.SbtUtil def getDependencyTree(project: Project): Unit = { val dependencyService = SbtDependencyService.getInstance(project) SbtUtil.getSbtProjects(project).foreach { sbtProject => sbtProject.getModules.foreach { module => val resolvedDeps = dependencyService.getResolvedDependencies(module) // 递归遍历构建依赖树 buildDependencyTree(resolvedDeps) } } } def buildDependencyTree(deps: Seq[org.jetbrains.sbt.model.SbtResolvedDependency]): Unit = { deps.foreach { dep => println(s"${dep.module}: ${dep.revision}") buildDependencyTree(dep.children) } } - 通过IntelliJ SBT Server执行内部命令:
借助SbtRunner直接执行sbt的dependencyTree命令,插件内部临时注入sbt-dependency-graph依赖,无需用户手动配置,且复用已有SBT Server进程,启动速度更快。示例:import org.jetbrains.sbt.runner.SbtRunner import org.jetbrains.sbt.SbtUtil def fetchDependencyTreeViaSbt(project: Project): Unit = { val sbtRunner = SbtRunner.getInstance(project) val targetProject = SbtUtil.getSbtProjects(project).head // 临时注入插件依赖并执行命令 val tempPluginSetting = """addSbtPlugin("net.virtual-void" % "sbt-dependency-graph" % "0.10.0-RC1")""" val command = s"""set every ${tempPluginSetting}; dependencyTree""" sbtRunner.runCommand(targetProject, command, output => { // 解析命令输出构建依赖树结构 parseDependencyTreeOutput(output) }) }
内容的提问来源于stack exchange,提问作者梦境迷离
相关产品推荐
相关产品推荐

