Skip to content

Java: make JDT-LS's null-analysis mode configurable - #1861

Open
Burgito wants to merge 1 commit into
oraios:mainfrom
Burgito:feat/jdtls-configurable-null-analysis-mode
Open

Java: make JDT-LS's null-analysis mode configurable#1861
Burgito wants to merge 1 commit into
oraios:mainfrom
Burgito:feat/jdtls-configurable-null-analysis-mode

Conversation

@Burgito

@Burgito Burgito commented Aug 13, 2026

Copy link
Copy Markdown

Serena hardcodes java.compile.nullAnalysis.mode to automatic, so JDT-LS enables the compiler
options required for annotation-based null analysis on any project with nullability annotations on
the classpath, and there is no way to ask for anything else short of patching the source. This PR
exposes that one value as ls_specific_settings.java.null_analysis_mode, keeping automatic as the
default.

Main reason to want it:

  • automatic is not inert. It changes the project's compiler options so that null analysis can run;
    on a project whose build owns those settings, having the language server adjust them is not always
    wanted.
  • One could argue that nullability warnings can be noise...

What changes

One new setting, accepting exactly the values JDT-LS accepts. Verified against the runtime Serena
downloads by default:

"java.compile.nullAnalysis.mode": {
  "type": "string",
  "enum": ["disabled", "interactive", "automatic"],
  "default": "interactive",
  "markdownDescription": "Specify how to enable the annotation-based null analysis.",
  "scope": "window"
}

vscode-java-1.54.0-923/extension/package.json, i.e. DEFAULT_VSCODE_JAVA_VERSION.

Why automatic remains the default

Vscode-java's own default is interactive, and Serena deliberately differs. That is worth
stating, because it is the reason this is a new knob rather than a switch to upstream's default.

In interactive mode JDT-LS enables nothing by itself: it asks the client over
language/actionableNotification, and the answer comes back as the client command
java.compile.nullAnalysis.setMode. Serena registers no
such command and discards that notification outright:

self.server.on_notification("language/actionableNotification", do_nothing)

src/solidlsp/language_servers/eclipse_jdtls.py:1384

So for Serena, interactive means the prompt is dropped and null analysis never turns on;
automatic is the only value that yields nullability diagnostics. Keeping it as the default means this PR changes no behaviour for anyone who does not set
the key. interactive is exposed for completeness rather than as a recommendation, and the docs say
as much.

Invalid values warn and fall back rather than raise

An unrecognized value logs a warning naming the valid values and falls back to automatic. It seemed the most coherent regarding the existing settings like on_stale_lock (Scala), project_roots, project_root_scan_depth, use_system_java_home ...

on_stale_lock (src/solidlsp/language_servers/scala_language_server.py:272-277) is the exact
structural analogue — an enum-valued ls_specific_settings string parsed through an Enum — and it
warns, so null_analysis_mode follows it, including the NullAnalysisMode enum shape. A typo in a
diagnostics knob also seems a poor reason to keep the Java language server from starting at all.

Scope

Two things left out deliberately — happy to add either if you would prefer:

  • The nonnull / nullable annotation lists stay hardcoded. They are JDT-LS settings too and
    could be exposed the same way, but I have no need for it and it widens the configuration surface
    for no demonstrated case.
  • The setting is not mixed into _compute_workspace_hash. That
    hash tracks import-affecting inputs (Maven/Gradle/JDK); null analysis is a compiler preference
    re-sent on every start. One consequence worth knowing: on a project JDT-LS has already imported,
    switching to automatic may only take full effect once it reprocesses the project.

Verification

  • 7 new test functions (17 cases once parametrized) in test/solidlsp/java/test_jdtls_path_resolution.py, next to the existing
    runtimes tests and using the same harness (no JDTLS started, no Java required): the default when
    unset; each of the three values reaching
    initializationOptions.settings.java.compile.nullAnalysis.mode; five invalid inputs (unknown
    value, wrong case, empty string, null, non-string) falling back with a warning; and the
    annotation lists unchanged under every mode.
  • pytest test/solidlsp/java/94 passed, including the @pytest.mark.java integration tests
    that do start JDT-LS.
  • poe lint and poe type-check → clean.

The tests were written before the implementation and observed failing first.

They assert the mode Serena sends, not that JDT-LS then emits different diagnostics — that would
need an annotated fixture and a real import. It is the same boundary the runtimes and
lombok_show_generated tests stop at.

Risk

Low. The default is the value that was previously hardcoded, so the generated initialize params are
identical for anyone who does not set the key; test_defaults_to_automatic_when_unset pins that.
Existing Java CI exercises exactly that unset-default population.

The diff also documents the setting in the EclipseJDTLS docstring and in the Java table of
docs/02-usage/050_configuration.md, which enumerates these settings and would otherwise be
incomplete.

Related

Disclosure

Prepared with the assistance of Claude Code (Claude Opus 5). The values and defaults quoted above
were read out of the bundled vscode-java runtime and the vscode-java sources rather than recalled,
and every file and line reference was checked against the tree. I reviewed and edited the text and
will answer follow-ups personally.

I also tested it locally with the local installation as a tool, as suggested in contribution guidelines.

English is not my first language, so please excuse me if I'm making any mistakes.

Checklist

  • This PR follows the guidelines in CONTRIBUTING.md regarding the scope of PRs.
  • For changes that add features or fix problems, I have added an entry to CHANGELOG.md, which concisely describes the change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant