Neovim + Java LSP 在 Play Framework sbt 项目中的缺失指南

发布: (2026年3月27日 GMT+8 01:32)
5 分钟阅读
原文: Dev.to

I’m ready to translate the article for you, but I need the full text of the post (the content after the source line) in order to do so. Could you please paste the article’s body here? Once I have it, I’ll provide a Simplified‑Chinese translation while keeping the source link, formatting, markdown, and code blocks exactly as they are.

简短回答

sbt-eclipse 生成 Eclipse 项目文件,JDTLS(Eclipse 的 Java 语言服务器)会读取这些文件。它们就是桥梁,其他都是配置细节。

如果你看到这里,可能已经尝试过 Metals,遇到瓶颈,搜索后失望而归。下面给出实际可行的配置方案。

项目背景

  • Play Framework 3.x,Java(非 Scala)
  • sbt 包含 7 个子模块,约 3 000 个源文件
  • 大量代码生成(OpenAPI、Avro、WSDL)
  • 团队使用 IntelliJ;你使用 Neovim

Metals 原生支持 sbt,但其 Java 支持极少(没有补全、悬停或组织导入)。一位 Metals 维护者甚至说:

“我无法想象有人会在完整的 Java 项目上使用 Metals。”

JDTLS 完整支持 Java,但只识别 Maven、Gradle 和 Eclipse 项目格式——它不认识 build.sbt。解决办法是让 sbt 生成 JDTLS 所需的文件:.classpath.project

我通过艰难经历学到的三件事

坑点原因
不要使用 ThisBuild / 范围sbt‑eclipseproject 级别读取键,而不是 ThisBuild。放在 ThisBuild 下的设置会被静默忽略。
ManagedSrc 至关重要如果没有它,生成的源代码(如 Play 路由、OpenAPI 代码生成、Avro)不会出现在 .classpath 中。仅有 ManagedClassesManagedResources 仍不足。
preTasks := Seq(Compile / compile)代码生成必须在创建 Eclipse 文件 之前 运行;否则受管的源目录尚未在磁盘上存在。

sbt‑eclipse 配置

全局添加插件

// ~/.sbt/1.0/plugins/plugins.sbt
addSbtPlugin("com.github.sbt" % "sbt-eclipse" % "6.2.0")

配置插件

// ~/.sbt/1.0/global.sbt
import com.typesafe.sbteclipse.core.EclipsePlugin.EclipseKeys

EclipseKeys.projectFlavor := EclipseProjectFlavor.Java
EclipseKeys.skipParents := false
EclipseKeys.withSource := true
EclipseKeys.preTasks := Seq(Compile / compile)
EclipseKeys.createSrc := EclipseCreateSrc.ValueSet(
  EclipseCreateSrc.Unmanaged,
  EclipseCreateSrc.Source,
  EclipseCreateSrc.Resource,
  EclipseCreateSrc.ManagedSrc,
  EclipseCreateSrc.ManagedClasses,
  EclipseCreateSrc.ManagedResources
)

生成 Eclipse 文件

sbt eclipse

此命令首先编译项目(触发代码生成),随后在根目录及每个子模块中创建 .classpath.project

将生成的文件添加到 .gitignore

.classpath
.project
.settings/

通过 Mason 安装 JDTLS

:MasonInstall jdtls

Neovim 的根目录检测配置

在一个多模块的 sbt 项目中,每个子模块都有自己的 build.sbt.project。如果这些文件出现在 root_markers 中,JDTLS 会把该子模块当作工作区根目录,从而导致跨模块导入失效。使用 .git 作为主要锚点:

vim.lsp.config("jdtls", {
  root_markers = {
    { "mvnw", "gradlew", "settings.gradle", "settings.gradle.kts", ".git" },
    { "pom.xml", "build.gradle", "build.gradle.kts", "build.xml" },
  },
})
vim.lsp.enable("jdtls")

注意: 嵌套数组需要 Neovim 0.11.3+。匹配到的第一个分组将被采用。

如果你更改了根目录检测方式或模块未被发现,请清除 JDTLS 的缓存:

rm -rf ~/.cache/nvim/jdtls/workspace/

然后重新启动 Neovim;JDTLS 将从头重新导入所有内容。

在 Neovim 中的完整 Java IDE 功能

  • 代码补全
  • 跳转到定义(跨模块)
  • 查找引用
  • 诊断
  • 整理导入
  • 重命名重构

运行/调试 Play 仍然通过终端中的 sbt (sbt run) 完成,因为 Play 的开发模式不使用标准的 main 方法。

类路径更新 – 在 build.sbt 中更改依赖后,重新运行 sbt eclipse 并重启 JDTLS。实际上,这种情况每月只会发生几次。日常编码、生成代码的更改以及切换分支(依赖相同)都不需要额外操作。

资源与工具

  • sbt‑eclipse – 使此成为可能的桥梁
  • nvim‑lspconfig – Neovim 的 JDTLS 配置
  • Mason.nvim – LSP 服务器安装器
  • nvim‑metals#503 – 讨论确认 Metals 在此用例下不可用
  • metals#1815 – Metals 团队对仅 Java 项目支持的立场
0 浏览
Back to Blog

相关文章

阅读更多 »

Neovim 0.12.0

NVIM v0.12.0 构建类型:Release LuaJIT 2.1.1774638290 发布说明 - 更新日志 https://github.com/neovim/neovim/commit/fc7e5cf6c93fef08effc183087a2c8cc9bf...

Java 异常处理简介

什么是 Exception Handling?Exception Handling 在 Java 中是一种处理运行时错误的机制,以便保持程序的正常流程。异常…