Ohhnews

分类导航

$ cd ..
foojay原文

Lathe:直接基于Maven构建工作的Java语言服务器

#lathe#java语言服务器#maven#lsp#开源工具

多年来,我在许多编辑器和 IDE 中编写过 Java,它们似乎都在同一个问题上挣扎。

对我来说,Java IDE 或语言服务器的难点从来不是代码智能。而是让项目结构正确。IDE 读取你的构建文件,然后试图从中猜测模块结构。随着时间的推移,Java 的编译器和运行时配置变得越来越复杂:注解处理器、模块系统等等。所以你经常会遇到熟悉的情况:代码在构建中能编译和运行,但在 IDE 中却不行。即使是最好的工具,也往往会在升级后破坏项目设置。

我一直遇到的问题

因此,当我想为我的 Java 项目尝试另一个编辑器时,现有的语言服务器一个都跑不起来,这并不令人意外。总是有东西出问题,而我也弄不清原因。最可能的原因是,我的项目大量使用注解处理和 Java 模块(JPMS)。

这让我开始思考:如果只是为了给我和同事解决这个问题,并在我们最喜欢的编辑器里获得真正的 Java IDE 体验,构建自己的语言服务器会有多难?多亏了语言服务器协议(LSP),这成为可能。LSP 是一个标准,允许一个服务器将相同的功能带到任何编辑器。不久前,这对单个开发者来说还太难了。AI 编程智能体让它成为可能。

想法

我构建的工具叫 Lathe——一个 Java LSP——其背后的想法很简单:不要猜测项目设置,而是从构建中捕获它。

我们使用 Maven,而 Maven 允许你注册一个构建扩展来包装编译器和测试执行框架。Lathe 利用这一点,直接从构建中记录编辑器所需的一切——类路径、模块路径、注解处理和测试配置——完全按照 Maven 所看到的那样。这就是捕获部分。

然后,语言服务器读取这些捕获的信息,并在你每次运行构建时刷新它。运行、测试和调试会根据捕获的内容进行重放,无需重新执行 Maven 构建。这也很自然:要更新编辑器,你只需运行一次构建,而你本来就会这么做。

所以,简而言之:如果你的 Maven 构建能工作,Lathe 也能工作。

它实际能做什么

Lathe 是一个标准语言服务器,因此它可以在任何支持 LSP 的编辑器中工作。我在 Neovim 中使用它,Neovim 有一个专用客户端,还添加了运行、测试和调试功能。它也能在 Emacs 中通过内置的 Eglot 工作,无需额外插件。VS Code 客户端已在计划中。

因为一切都来自真实的构建,这些功能只是反映编译器已经知道的内容。以下是完整列表,按类别分组:

  • 代码智能 —— 带自动导入的补全;跳转到定义和声明(可进入你自己的代码、依赖项和 JDK 源码);查找引用;调用层次结构;类型层次结构;实现和子类型;文档与工作区符号搜索,支持驼峰匹配(ASF 可找到 AbstractServerFactory);签名帮助;悬停显示 Javadoc;文档高亮;代码折叠;以及语义高亮。
  • 诊断和重构 —— 为你的构建提供精确的 javac 错误和警告,外加未使用的私有成员和局部变量的警告;快速修复和重构(添加缺失的导入、添加 throws、用 try/catch 包裹、提取变量、常量或字段等);以及可选的 google-java-format。
  • 运行、测试和调试 —— 运行 main、运行测试(单个方法、类或包),以及完整的调试,支持断点、单步执行、变量检查和表达式求值。一切都从构建中重放,无需重新运行 Maven。
  • 脚手架 —— 创建新的类、接口、record、enum、注解或测试,并为你放到正确的模块和包中。

[LOADING...]

开始使用

你需要 Java 21+(与你的构建所使用的 JDK 相同)和 Maven 3.x。设置分为三步,而且只需做一次。

首先,在项目根目录注册 Lathe 扩展——可以在 .mvn/extensions.xml 中,也可以在根 pom.xml 的 <build><extensions> 下:

$ xml
<extension>
    <groupId>io.github.ag-libs</groupId>
    <artifactId>lathe-maven-extension</artifactId>
    <version>...</version> <!-- latest version from Maven Central -->
</extension>

你可以在 Maven Central 上找到最新版本。

然后运行一次构建以捕获所有内容,并将 .lathe/ 添加到 .gitignore:

$ bash
mvn clean test -Dlathe.capture.only=true

最后,设置你的编辑器。对于 Neovim,让你的插件管理器指向构建解压到 ~/.cache/lathe/current/neovim 的客户端。对于 Emacs,不需要插件——在 init.el 中加一行,将内置的 Eglot 指向 Lathe 的启动器即可。

之后它会自动保持同步:每次构建都会刷新配置,Lathe 还会注意到编辑器之外的文件变化,例如执行 git pull 之后。完整的设置(包括编辑器配置)在 README 中。

目前进展

Lathe 是 Apache 2.0 许可证下的开源项目。它还处于早期阶段——我构建它本来是为了解决自己的问题,现在它已经能在我和同事的真实模块化项目中很好地做到这一点,这些项目使用了注解处理。Neovim 客户端是最完整的;Emacs 通过 Eglot 使用;VS Code 客户端是下一步。

如果这听起来也是你遇到的问题,我很想知道它是否能帮到你。代码、完整设置和简短演示都在 GitHub 上,构件在 Maven Central 上。非常欢迎错误报告和反馈——请提交 issue。

分享此页面

发现错误,或想补充内容?在 GitHub 上编辑此页

[LOADING...]

作者

Alexey Gavrilov

来自挪威的 Java 开发者,拥有 25 年以上经验。Lathe 的作者,这是一个直接基于你的 Maven 构建工作的 Java 语言服务器;此外还编写了一些其他有用的开源 Java 库。

加入讨论