fix(java): Run jdtls with a Lombok agent and show build errors at launch (#9)

* fix(java): Run jdtls with a Lombok agent and show build errors at launch

jdtls compiles with ECJ, which only generates Lombok members when the
server JVM runs -javaagent:lombok.jar. Nothing put it there, so @Data /
@Setter classes lost their accessors and Run launched stale classes
with "Unresolved compilation problem" stubs and no explanation.

- Projects whose build files mention Lombok get the newest jar: the
  IDE-managed one (new "Lombok (jdtls agent)" tool, latest release from
  Maven Central), else ~/.m2 (incl. settings.xml localRepository) or the
  Gradle cache. Each agent gets its own jdtls workspace so everything is
  rebuilt with it.
- Settings › Languages & Frameworks › Java › JVM options
  (java.jdt.ls.vmargs); a Lombok agent there wins.
- Run (and Debug, as a notification) list the first compile errors when
  the build has errors, plus a hint when Lombok is missing or older than
  1.18.34.

Fixes #3

* fix(java): Base the Lombok hint on the agent jdtls actually runs

A Lombok agent in Settings › Java › JVM options wins over the managed
and cached jars, but the launch hint still looked only at those: with
no cached jar it said Lombok was missing, and with an old cached one it
blamed that version although jdtls ran the user's. The hint and the
startup warning now use the user's agent (version from its file name).
Цей коміт міститься в:
l0ng-ai authored and GitHub committed 2026-10-23 18:46:13 +08:00
1 джерело 555ea8901f
коміт acf6931017
24 files changed
+687 -19

No files matched your search

+29
Переглянути файл
@@ -1,6 +1,7 @@
import { beforeEach, describe, expect, it } from "vitest";
import type { JavaLaunchInfo, RunConfig } from "@/platform/ipc";
import {
formatCompileErrors,
joinJavaArgs,
jdwpListeningPort,
parseJavaArgs,
@@ -170,6 +171,31 @@ describe("application configurations", () => {
});
});
describe("java compile errors", () => {
const base: Omit<JavaLaunchInfo, "errors" | "errorCount" | "hints"> = {
build: "withErrors",
projectRoot: "/p",
classPaths: [],
modulePaths: [],
javaHome: null,
javaExec: null,
};
it("lists the first errors, counts the rest and adds hints", () => {
const report = formatCompileErrors({
...base,
errors: [{ path: "/p/src/A.java", line: 72, column: 5, message: "The method getUsername() is undefined" }],
errorCount: 3,
hints: ["Install Lombok"],
});
expect(report).toBe(
"/p/src/A.java:72:5: error: The method getUsername() is undefined\n" +
"… and 2 more errors (see the Problems tool window)\nInstall Lombok\n",
);
expect(formatCompileErrors({ ...base, errors: [], errorCount: 0, hints: [] })).toBe("");
});
});
describe("java command lines", () => {
const info: JavaLaunchInfo = {
build: "succeeded",
@@ -178,6 +204,9 @@ describe("java command lines", () => {
modulePaths: [],
javaHome: "/jdk21",
javaExec: "/jdk21/bin/java",
errors: [],
errorCount: 0,
hints: [],
};
it("parses VM options, main class and program arguments", () => {