Files
openidea/docs/zh/languages/java.mdx
T

146 lines
14 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
title: "Java 与 Kotlin"
description: "OpenIDEA 如何借助 JDT LS、Kotlin LSP、Maven 和 Gradle 为 Java 与 Kotlin 项目提供代码智能、构建、运行、测试和调试。"
---
Java 的代码智能由 Eclipse JDT Language Server(jdtls)提供,OpenIDEA 还为它加载了一组随应用发布的扩展 bundle;Kotlin 使用 JetBrains 的 Kotlin LSP。Maven 和 Gradle 项目会自动导入,两种语言的运行、测试和调试都走同一套运行配置。与其他语言的对比见[语言支持总览](/zh/languages/index)。
## 语言服务器
| 语言 | 服务器 | 备选 | 调试器 |
| ------------------- | -------------------------------------- | -------------------------------------------------------- | ------------------------------------- |
| Java | Eclipse JDT Language Server(`jdtls`) | `kmp-lsp` | Microsoft java-debug,加载在 jdtls 内 |
| Kotlin | Kotlin LSP(JetBrains,`kotlin-lsp`) | Kotlin Language Server(fwcd,`kotlin-language-server`) | Kotlin Debug Adapter(fwcd) |
| Groovy、Gradle 脚本 | `groovy-language-server`(需自行提供) | | |
| JSP | 无(仅语法高亮) | | |
备选服务器只在排在它前面的服务器未安装时才会启动。想手动指定,打开 **设置 › 语言和框架 › 语言服务器**,选中其中一个服务器,在 **Java 语言服务器**(或 Kotlin 语言服务器)里选择:**自动** 使用第一个可用的,**无** 关闭代码智能。这个选择可以全局生效,也可以只对当前项目生效。
`kmp-lsp` 不运行 JVM,提供基于语法的 Java 代码智能,没有 JDT 的编译分析、Lombok 支持和 JDT 的重构。构建和运行 Java “应用程序”配置、类路径发现以及 Java 调试器都需要 jdtls。
### 随 IDE 提供的部分
在原版 jdtls 之上,OpenIDEA 会加载仓库 [`java/`](https://github.com/l0ng-ai/openidea/tree/main/java) 目录里的扩展 bundle:
- **java-usages**:查找用法能区分读和写;对字段,还会一并找出它的 getter、setter 和 builder(包括 Lombok 生成的)。查找用法默认只搜项目源码(**项目文件**),选择 **项目和库** 时才会搜索依赖 jar。
- **Spring 配置导航**:见 [Spring](#spring)。
- **kotlin-bridge**:在 Java 与 Kotlin 混合的 Maven 项目里,让 Java 代码能看到 Kotlin 类。见下文“Maven 项目中的 Kotlin”。
- **Lombok**:应用内置一个打过补丁的 Lombok agent(1.18.48,修复了在当前 JDT LS 上的问题),无需下载。
没有源码的库类会以反编译后的 `jdt://` 文档打开。依赖有源码包时,jdtls 会下载 Maven 和 Eclipse 源码。
## 环境配置
### 安装服务器
打开 Java 或 Kotlin 文件时,如果对应的服务器缺失,会弹出通知并提供 **安装** 按钮。也可以在 **设置 › 语言和框架 › 语言服务器** 里安装、重新安装或卸载每个工具。所有工具都装进 IDE 自己的工具目录,不需要管理员权限:
| 工具 | 来源 |
| ----------------------------------- | ---------------------------------------------------------- |
| Eclipse JDT Language Server | download.eclipse.org 上的最新 milestone |
| Java 调试器(Microsoft java-debug) | Open VSX 上的 `vscjava.vscode-java-debug` 扩展 |
| Lombok(jdtls agent) | 随应用内置 |
| Kotlin LSP(JetBrains) | `Kotlin/kotlin-lsp` 的 GitHub release |
| Kotlin Language Server(fwcd) | `fwcd/kotlin-language-server` 的 GitHub release,需要 Java |
| Kotlin Debug Adapter | `fwcd/kotlin-debug-adapter` 的 GitHub release,需要 Java |
| kmp-lsp | `Hessesian/kmp-lsp` 的 GitHub release |
`PATH` 上已有的 `jdtls`(Homebrew、Scoop 或 release 压缩包)也能直接用。OpenIDEA 直接在 JVM 上启动它,不经过它自带的 Python 启动脚本,所以不需要装 Python。没装 java-debug 就开始调试时,IDE 会提示安装,并带着这个 bundle 重启 jdtls。
Groovy 没有安装程序:需要自行构建 [groovy-language-server](https://github.com/GroovyLanguageServer/groovy-language-server),以 `groovy-language-server` 的名字放到 `PATH` 上,或在 **语言服务器** 页面里指定可执行文件。
### JDK 检测
OpenIDEA 会在这些位置查找已安装的 JDK:`JAVA_HOME`、`PATH` 上的 `java`、`/Library/Java/JavaVirtualMachines`(系统级和用户级)、`/usr/lib/jvm`、Homebrew、SDKMAN、mise、asdf、`~/.jdks`,以及 Windows 上 `Program Files` 下常见的厂商目录。IDE 自己下载的 JDK 也会被找到。JDK 列表旁的 **重新检测** 可以重新扫描。
**设置 › 语言和框架 › Java** 里有两项 JDK 设置:
- **项目 JDK › SDK**:用于编译和运行项目。它是 jdtls 的默认运行时、运行/调试使用的 JDK,也是 Maven 和 Gradle 的 `JAVA_HOME`。选 **自动** 时,每个模块使用与其目标 Java 版本匹配的已安装 JDK。
- **语言服务器 › JDK**:只用来运行 jdtls,因此 Java 8 或 17 的项目也能用上新版 jdtls。选 **自动** 时,项目 JDK 版本够新就用它,否则用第一个满足要求的已安装 JDK;一个都没有时,会自动下载 Eclipse Temurin 到单独的语言服务器运行时目录。
jdtls 需要 JDK 21 或更高版本,部分 jdtls 版本要求更高,OpenIDEA 会从已安装的 jdtls 中读取实际要求。检测到的每个 JDK 还会作为运行时(`JavaSE-17`、`JavaSE-21`……)注册给 jdtls,所以目标是 Java 17 的模块会针对 JDK 17 编译,而不是针对运行 jdtls 的那个 JDK。
**语言级别** 在构建文件没有指定时决定 Java 源码和字节码级别。每个 JDK 列表里都有 **下载 JDK…**,可以选择版本,把 Eclipse Temurin 下载到 IDE 的 JDK 目录。当 jdtls、某个运行配置或 Maven/Gradle 同步找不到足够新的 JDK 时,也会提示同样的下载。
Kotlin Language Server(fwcd)最高只能在 Java 21 上运行。如果 `JAVA_HOME` 指向更新的 JDK,IDE 会改用已安装 JDK 中符合要求的最新版本来启动它。
### 内存与 JVM 选项
每个项目窗口各自启动一个 jdtls,有独立的工作区和索引。jdtls 默认使用以下 JVM 选项:
```text
-XX:+UseG1GC -XX:G1PeriodicGCInterval=60000 -XX:MinHeapFreeRatio=10 -XX:MaxHeapFreeRatio=30 -Xmx2G -Xms100m
```
G1 加上周期性回收,可以在导入或构建结束后把内存还给系统。要调整上限,在 **设置 › 语言和框架 › Java › 语言服务器 › JVM 选项** 中填写,例如 `-Xmx1g` 或 `-Xmx4g`。你设置的选项会替换同一项的默认值;指定其他回收器(如 `-XX:+UseZGC`)时,默认的回收器相关选项会全部去掉。该设置可以全局配置,也可以按项目配置。
**在构建间共享 JDT LS** 让一个本地项目窗口里所有关联的构建共用一个 jdtls,而不是每个构建一个。不同项目窗口之间仍然是各自独立的进程。
jdtls 的工作区保存在 IDE 的数据目录(`lsp/jdtls/`)中,不在项目里;jdtls 也不会往项目里写 `.project`、`.classpath` 或 `.settings`。见[数据目录与日志](/zh/reference/data-directories)。
### Lombok
项目用到 Lombok 时(在构建文件、继承的父 POM 或 Gradle 构建中声明,或源码里有相关 import),OpenIDEA 会给 jdtls 加上 Lombok agent。默认使用 **语言服务器** 页面里的那个,也就是内置的版本;没有时会退回到 Maven 或 Gradle 缓存里最新的 Lombok。你在 **JVM 选项** 里自己写的 `-javaagent` 优先。项目自身的 Lombok 依赖不会被改动。
## 构建工具
jdtls 会自动导入 Maven 和 Gradle 项目(包括 Gradle wrapper)。没有构建文件的目录会作为普通 Java 项目打开,`lib/` 下的 jar 会加入类路径。OpenIDEA 还提供 **Maven** 和 **Gradle** 工具窗口,用来执行目标和任务、重新加载、切换 profile 以及分析依赖。相关设置在 **设置 › 构建、执行、部署 › Maven** 和 **Gradle**:
- Maven:**JRE**、**Maven 主路径**(默认用项目的 `mvnw`,没有则用 `PATH` 上的 `mvn`)、**用户设置文件**、**Toolchains 文件**、**本地仓库**、**活动 profiles**、**线程数** 和 **使用 Maven Daemon (mvnd)**。在 Maven 工具窗口里选的 profile 也会传给 jdtls,编辑器看到的依赖与该 profile 一致。
- Gradle:**构建和运行使用**(Gradle 或 OpenIDEA)、**Gradle 使用的 JVM**、**分发**(Gradle 包装器或本地安装)、**Gradle 主路径** 和 **Gradle 用户主目录**。
IDE 会把代理设置传给 jdtls,所以在代理环境下也能解析依赖。工具窗口的用法见[构建工具](/zh/guide/build-tools)。
### Maven 项目中的 Kotlin
在含 Kotlin 源码的 Maven 项目里,每次保存后 OpenIDEA 会在后台用项目自己的 Maven 配置构建 Kotlin 代码,输出到一个私有目录,再把编译好的 Kotlin 类作为库交给 jdtls。这样同一模块或其他模块的 Java 代码就能调用 Kotlin 代码。这次构建的错误会以 `kotlin-bridge` 的名义出现在 **问题** 中;在下一次构建成功之前,继续使用上一次成功的结果。这个桥接只覆盖编译后的 Kotlin API,从 Java 跳转到 Kotlin 源码、分析未保存的 Kotlin 修改以及跨语言重构都不在其中。
## 运行与测试
| 对象 | 运行方式 |
| ----------------------------- | -------------------------------------------------------------------------------- |
| `main` 方法 | **应用程序** 配置,使用模块的运行时或测试类路径;支持 Java 25 的实例 `main` 方法 |
| `@SpringBootApplication` 类 | **Spring Boot** 配置,可设置活动 profile 和更新操作 |
| 可执行 jar | **JAR 应用程序** 配置 |
| WAR | **Tomcat 服务器** 配置,运行在本地 Tomcat 安装上(IDE 不会往安装目录里写东西) |
| JUnit 4、JUnit 5、TestNG 测试 | Maven(Surefire `-Dtest=…`)或 Gradle(`--tests …`)测试配置 |
main 方法、测试类和测试方法旁的边栏图标会创建这些配置;Maven 和 Gradle 的运行配置会从构建文件中自动检测。对 Gradle 项目,**构建和运行使用** 决定“应用程序”是作为 Gradle 的 `JavaExec` 任务运行(默认),还是由 OpenIDEA 用 jdtls 给出的类路径直接启动。
测试结果从 Maven 和 Gradle 生成的 JUnit XML 报告中读取,通过的测试也会列出;测试树支持只重跑失败的测试。Gradle 运行配置的 VM 选项会作用到 Gradle fork 出来的 JVM(`run`、`bootRun`、`test`)。类路径超出命令行长度限制时(Windows 上常见),会改用参数文件或只含 manifest 的 jar。
另见[运行配置](/zh/guide/run)和[测试](/zh/guide/testing)。
## 调试
Java 调试使用 jdtls 内的 Microsoft java-debug,Kotlin 调试使用 Kotlin Debug Adapter。可以调试:
- “应用程序”、Spring Boot、“JAR 应用程序”和“Tomcat 服务器”配置。
- 会启动 JVM 的 Maven 和 Gradle 配置(测试、`spring-boot:run`、`bootRun`、`run`):IDE 会加上 JDWP agent,等 JVM 就绪后自动附加,输出和测试树仍留在运行工具窗口里。
- 在别处启动的进程:使用 **远程 JVM 调试** 配置。
**运行 › 调试操作 › 重新加载已更改的类**(HotSwap)会编译你的修改并加载到正在运行的会话中。Spring Boot 和 Tomcat 配置还支持 **运行 › 更新应用**(`⌘F10` / `Ctrl+F10`),行为由 **执行“更新”操作时** 选项决定。
另见[调试](/zh/guide/debugging)。
## 框架支持
### Spring
- **Spring Boot 运行配置**:根据 `@SpringBootApplication` 类创建,默认显示在 **服务** 工具窗口中。
- **配置导航**:在 `application.yml` 或 `.properties` 的键上转到定义,会打开绑定到它的 Java 成员(`@ConfigurationProperties`、`@Value`、`Environment.getProperty`);反过来,从 Java、YAML、properties 或 Spring XML 里的 `${…}` 占位符也能跳到配置键。依赖中 `spring-configuration-metadata.json` 描述的键会跳到对应的源类。对配置键执行 **查找用法**,会同时列出配置声明和 Java 中的使用处。
- **Spring Web 端点**:Java 和 Kotlin 控制器中的请求映射旁有边栏图标,还有 **在 HTTP 客户端中生成请求** 和 **为控制器生成请求** 两个操作,会把请求写进一个临时 `.http` 文件。随处搜索的 **全部** 标签页可以按请求路径搜索。见 [HTTP Client](/zh/guide/http-client)。
- **Facet**:在 **项目结构**(`⌘;` / `Ctrl+Alt+Shift+S`)里记录模块使用的框架(Web、Spring、JPA)。添加 Web Facet 还会把其中的 `WEB-INF/lib/*.jar` 加入 jdtls 的类路径。
### MyBatis
MyBatis mapper 接口与 XML 语句之间的跳转由 MyBatis Navigator 插件([`plugins/official/mybatis`](https://github.com/l0ng-ai/openidea/tree/main/plugins/official/mybatis))提供,不属于 IDE 本体。
## 已知限制
- 每个项目窗口运行一个 jdtls,同时打开多个大项目时内存会叠加。可以在 **JVM 选项** 中调低 `-Xmx`,或关闭暂时不用的窗口。**在构建间共享 JDT LS** 只在单个窗口内有效。
- 没有 jdtls 时(例如只用 `kmp-lsp`),“应用程序”配置、依赖类路径的功能和 Java 调试都不可用。
- Java 测试通过 Maven 或 Gradle 运行,两者都没有的项目没有测试运行器。
- Kotlin 桥接只支持 Maven,只把编译后的 Kotlin 类暴露给 Java,不提供从 Java 到 Kotlin 源码的跳转或重构。
- Groovy 需要自行构建 `groovy-language-server`,JSP 只有语法高亮。