Java (JDT-LS): allow registering additional JRE/JDK runtimes via config (#1715)

* Java (JDT-LS): allow registering additional JRE/JDK runtimes via config

JDT-LS resolves each imported module's JRE_CONTAINER/.../JavaSE-NN/
classpath entry against its own "Installed JREs" list, which Serena
previously hardcoded to a single JavaSE-21 entry pointing at the
bundled JRE. Projects whose source/target level exceeds that bundled
JDK (e.g. sourceCompatibility = VERSION_25) get a container that never
resolves, so every JDK type -- java.lang.Object, java.util.*, etc. --
comes back "cannot be resolved", silently breaking diagnostics and
cross-module resolution. There was no config key to tell JDT-LS about
an installed newer JDK.

Add an optional `runtimes` list under ls_specific_settings.java,
mirroring VS Code's java.configuration.runtimes shape (name, path,
optional default/sources/javadoc). Entries are validated (name+path
required, path must exist) via the new _resolve_configured_runtimes(),
then merged with the bundled JavaSE-21 default: configured runtimes
extend the list; an entry reusing the "JavaSE-21" name overrides the
bundled one; if a configured entry claims `default`, the bundled
runtime's own default flag is cleared so JDT-LS doesn't see two
defaults. The `runtimes` key is also added to the JDTLS workspace-hash
inputs so changing it lands in a fresh workspace instead of reusing a
stale Buildship/Maven import.

Testing: added 14 unit tests in
test/solidlsp/java/test_jdtls_path_resolution.py covering
_resolve_configured_runtimes validation (missing keys, wrong types,
nonexistent paths) and the merge behavior in
_create_base_initialize_params (extension, name-collision override,
default hand-off). Ran `poe format`, `poe type-check`, and
`pytest test/solidlsp/java -m "not java"` (69 passed, 8 deselected
real-JDTLS tests that require a JDK) locally.

Fixes #1478

* docs: document java.runtimes in configuration guide

Address review feedback on #1715 by documenting ls_specific_settings.java.runtimes
in 050_configuration.md (settings table, note, and example).

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: arimu1 <19286898+arimu1@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
authored and GitHub committed 2026-07-19 16:03:25 +02:00
1 parent a9067050f2
commit 18d4cc007b
4 files changed
+231 -4

No files matched your search

+18
View File
@@ -697,6 +697,7 @@ The following settings are supported for the Java language server:
| `gradle_wrapper_enabled` | `false` | Use the project's Gradle wrapper (`gradlew`) instead of the bundled Gradle distribution. Enable this for projects with custom plugins or repositories. |
| `gradle_java_home` | `null` | Path to the JDK used by Gradle. When unset, Gradle uses `JAVA_HOME` if `use_system_java_home` is enabled and `JAVA_HOME` is set; otherwise it falls back to Serena's bundled JRE. |
| `use_system_java_home` | `false` | Use the system's `JAVA_HOME` environment variable for JDTLS itself and, when `gradle_java_home` is unset, Gradle import. Enable this if your project requires a specific JDK vendor or version for Gradle's JDK checks. |
| `runtimes` | `[]` | Extra JRE/JDK entries registered with JDT-LS via `java.configuration.runtimes`. Use this when a project's source/target level exceeds the JDK JDT-LS itself runs on (currently JDK 21 in default vscode-java VSIX mode). Each entry is a mapping with required `name` (e.g. `JavaSE-25`, matching the `JavaSE-NN` container the build tool requests) and `path` (JDK/JRE home directory; must exist), plus optional `default`, `sources`, and `javadoc` (passed through to JDT-LS). Entries extend rather than replace the bundled `JavaSE-21` runtime; an entry that reuses the `JavaSE-21` name overrides the bundled one. Changing this setting invalidates the JDTLS workspace hash so a fresh import is performed. |
| `gradle_version` | `8.14.2` | (vscode-java mode only) Override the Gradle distribution version Serena downloads by default. |
| `vscode_java_version` | `1.54.0-923` | (vscode-java mode only) Override the bundled `vscode-java` runtime bundle version Serena downloads by default. |
| `intellicode_version` | `1.2.30` | (vscode-java mode only) Override the IntelliCode VSIX version Serena downloads by default. |
@@ -716,6 +717,10 @@ Notes:
- In upstream-jdtls mode the `gradle_version`, `vscode_java_version`, `intellicode_version`,
`intellicode_xmx`, `intellicode_xms` settings are silently ignored — they only apply to the
vscode-java VSIX mode.
- Without `runtimes`, JDT-LS only knows about the bundled `JavaSE-21` JRE. Projects that request a newer
container (e.g. `sourceCompatibility = JavaVersion.VERSION_25`) then fail to resolve JDK types such as
`java.lang.Object`. Register the matching installed JDK via `runtimes` instead of symlinking over Serena's
bundled JRE directory.
Example: upstream-jdtls mode (offline / corporate network):
@@ -736,6 +741,19 @@ ls_specific_settings:
use_system_java_home: true
```
Example: register an additional JDK for a project targeting a newer Java version:
```yaml
ls_specific_settings:
java:
runtimes:
- name: JavaSE-21
path: /usr/lib/jvm/java-21-openjdk
- name: JavaSE-25
path: /home/user/Java/jdk25
default: true
```
#### Kotlin
Serena uses [JetBrains' Kotlin Language Server](https://github.com/Kotlin/kotlin-lsp) for Kotlin support.