Skip to content

feat(ide): IntelliJ-style Java authoring — New → Java scaffolding + full Monaco Java IntelliSense#6076

Open
iliyan-velichkov wants to merge 9 commits into
masterfrom
feat/web-ide-java-authoring
Open

feat(ide): IntelliJ-style Java authoring — New → Java scaffolding + full Monaco Java IntelliSense#6076
iliyan-velichkov wants to merge 9 commits into
masterfrom
feat/web-ide-java-authoring

Conversation

@iliyan-velichkov

Copy link
Copy Markdown
Contributor

What & why

Authoring client Java in the browser IDE is currently bare: the only Java entry in the workbench New menu is a single "Java Service" template, and the Monaco editor wires JDT.LS for read-only features (completion, hover, diagnostics). This PR makes Java development in the web IDE feel like IntelliJ — fast, strong-interface scaffolding plus a real completion/generation/refactoring layer.

1. New → Java submenu (Projects view)

Right-click a project or folder → New → Java:

  • Package — type com.test.iliyan, the full nested folder chain is created.
  • Class, Interface, Enum, Annotation, Record, Exception — base types.
  • Controller, Job, Listener, WebSocket, Repository — pre-wired strong-interface skeletons (@Controller+@Get, implements JobHandler, implements MessageHandler, implements WebsocketHandler, @Repository extends JavaRepository<T>).

Naming follows IntelliJ: a fully-qualified name (com.test.MyClass) creates the package folders and emits the matching package declaration (mirroring the file's path relative to the project root, as the client-Java compiler requires); a simple name lands in the selected folder with no package line.

All Java-specific logic (name parsing/validation + skeleton generation) lives in a new pure, dependency-free helper view-projects/js/java-new.js; projects.js only orchestrates dialog → nested folder → file → open through the existing WorkspaceService (folder creation relies on the server's forceMkdir to create parents).

2. Java IntelliSense (editor-monaco LSP client)

Extends editor-monaco/js/lsp/java-lsp-client.ts (rebuilt bundle committed):

  • Auto-import on completioncompletionItem/resolve pulls additionalTextEdits, so accepting a type inserts its import.
  • Dirigible SDK priority — completions under org.eclipse.dirigible.sdk.* rank above everything else.
  • Code actions — quick-fixes, organize imports, and generate constructor / getters / setters / toString / equals&hashCode with a member-picker dialog (BlimpKit DialogHub).
  • Rename symbol, find references, format document.
  • Server→client workspace/applyEdit + workspace/configuration handling so command-driven edits land.
  • The initialize capabilities are expanded (codeAction literal/resolve, completion resolve, rename prepare, references, formatting, executeCommand, applyEdit) since JDT.LS gates features on them.

3. Format on save for Java

Registering the Java document-formatting provider enables the editor's existing TypeScript format-on-save path for Java automatically — same global "Auto-Formatting" toggle and "Toggle Auto-Formatting" action, no Java-specific branch.

Tests

  • CreateJavaArtifactsIT drives New → Java end to end for the base types, the skeletons, a fully-qualified class and a nested package, asserting the created folders, files, package declarations and skeleton signals over the workspace REST API (deterministic — no Monaco DOM scraping).
  • Framework: Browser.hoverOnElementByAttributePatternAndText (for cascading submenu navigation) + Workbench.createJavaArtifact.

Verification

  • mvn -P quick-build install of view-projects + editor-monaco (the Maven esbuild step reproduces the committed java-lsp-client.js byte-for-byte), tsc --noEmit clean.
  • java-new.js skeleton/parse logic checked under Node; framework + IT modules compile.
  • The deep LSP behaviour (completion/generate/rename) is verified manually against the running JDT.LS — the exact JDT.LS generate command IDs are wired per the language-server protocol and validated against the bundled server. The CreateJavaArtifactsIT UI flow runs under the matched Chrome/ChromeDriver in CI.

🤖 Generated with Claude Code

iliyan-velichkov and others added 2 commits June 23, 2026 11:36
…ull Monaco Java IntelliSense

Make writing client Java in the browser IDE feel like IntelliJ.

New → Java submenu (Projects view):
- Package (creates the nested folder chain from a dotted name)
- Class, Interface, Enum, Annotation, Record, Exception
- Controller, Job, Listener, WebSocket, Repository — strong-interface skeletons
A fully-qualified name (com.test.MyClass) creates the package folders and the
matching package declaration; a simple name lands in the selected folder. Logic
lives in a new pure helper js/java-new.js; projects.js orchestrates dialog →
nested folder → file → open via the existing WorkspaceService.

Java IntelliSense (editor-monaco LSP client):
- Auto-import on completion (completionItem/resolve → additionalTextEdits)
- Dirigible SDK suggestions ranked first (sortText bucketing)
- Code actions: quick-fixes, organize imports, and generate
  constructor/getters/setters/toString/equals&hashCode with a member-picker dialog
- Rename symbol, find references, document formatting
- Server→client workspace/applyEdit + configuration handling
- Format-on-save for Java reuses the existing TypeScript auto-format mechanism via
  the new formatting provider (same global toggle)

Tests:
- CreateJavaArtifactsIT drives New → Java end to end and asserts folders, files,
  package declarations and skeleton signals over the workspace REST API
- Browser.hoverOnElementByAttributePatternAndText + Workbench.createJavaArtifact

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…avaArtifactsIT pass

JDT.LS was launched with -Xmx512m, which OOMs ("Java heap space") while indexing
the full platform classpath (~1000+ entries), killing the language server and with
it completion / auto-import / code actions. Make the max heap configurable via
DIRIGIBLE_JAVA_LSP_MAX_HEAP (DirigibleConfig.JAVA_LSP_MAX_HEAP) and default it to 2g.

Test framework: CreateJavaArtifactsIT now drives the nested New → Java → <item>
context menu reliably. Replaced the strict hover/visibility approach (which cannot
reach a collapsed 3rd-level submenu in headless Chrome, where moveToElement does not
fire mouseenter) with Browser.clickCascadingMenuItem, which scopes to the open
context menu and drives its own Angular mouseenter/click handlers in a single
in-frame script. Verified: the IT passes end to end (package folders, package
declarations and strong-interface skeleton signals all asserted over the workspace
REST API).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@iliyan-velichkov

Copy link
Copy Markdown
Contributor Author

Follow-up while testing locally

JDT.LS heap fix. JDT.LS launched with -Xmx512m, which throws OutOfMemoryError: Java heap space while indexing the full platform classpath (~1000+ entries), killing the language server (and with it completion / auto-import / code actions). Max heap is now configurable via DIRIGIBLE_JAVA_LSP_MAX_HEAP (DirigibleConfig.JAVA_LSP_MAX_HEAP), default 2g. (commit 880a01b)

Integration test now green. CreateJavaArtifactsIT passes end to end. Reaching the nested New → Java → <item> menu needed a headless-robust navigator — Browser.clickCascadingMenuItem scopes to the open context menu and drives its own Angular mouseenter/click handlers in one in-frame script (a strict hover/visibility approach can't reach a collapsed 3rd-level submenu headless: moveToElement doesn't fire mouseenter, and per-step frame switches collapse the menu).

iliyan-velichkov and others added 7 commits June 23, 2026 13:42
…ntity is an input

- After creating a Java artefact the project tree now expands to and selects the new
  file (building/reusing the package folder nodes) instead of reloading the project
  node, which collapsed the structure.
- The Repository skeleton no longer reuses the repository class name as its entity
  type parameter (DemoRepo → JavaRepository<DemoRepo>). The dialog now prompts for the
  entity type (simple or fully-qualified; a qualified name adds the import), producing
  e.g. JavaRepository<Country> with super(Country.class).
- CreateJavaArtifactsIT + Workbench.createJavaArtifact updated for the entity prompt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…mpletion

- Completion now propagates JDT.LS's isIncomplete so Monaco re-queries as you type
  (fixes the first Ctrl+Space showing nothing), and forwards the real trigger
  kind/character plus filterText/preselect/commitCharacters for correct filtering.
- Registered a Monaco editor opener: Go to Definition / Find References to a symbol
  in another workspace file now opens that file in the IDE and reveals the line
  (the single-file editor previously had no model for other files, so navigation
  silently did nothing). Same-file targets still jump within the editor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… file

Renaming a Java symbol (F2) now applies JDT.LS's full rename WorkspaceEdit across the
whole workspace instead of only the current file:

- Text edits in every referencing file are applied and persisted (read-modify-write
  over the workspace REST API, CSRF-guarded); the current file goes through the live
  Monaco model + save.
- RenameFile operations are honoured, so renaming a public class/interface/enum also
  renames its .java file and updates all references; when that file is the one being
  edited, the editor tab switches to the new file.
- Other open editors reload the changed files (dirty editors are skipped to avoid
  clobbering unsaved work) via a new monaco.file.reload topic.

Falls back to current-file-only rename if the IDE persistence hook is unavailable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…s, semantic colors, CodeLens, override/implement, keywords

Adds JDT.LS-backed language features to the Monaco Java editor:

Navigation & structure:
- Outline / breadcrumbs / sticky scroll (documentSymbol), code folding
  (foldingRange), occurrence highlight (documentHighlight), Go to Implementation
  and Go to Type Definition (reusing the cross-file editor opener), Format
  Selection (rangeFormatting) and Smart Expand Selection (selectionRange).

Editor intelligence:
- Inlay hints (parameter names + inferred types) and semantic-token highlighting
  (legend captured from the initialize result; semanticHighlighting enabled on the
  editor).
- CodeLens with "N references / N implementations" (click opens the peek).
- Override/Implement Methods wired into the existing member-picker generate flow.
- Always-available Java keyword completion, ranked below SDK/LSP results.

Advertises the matching client capabilities and enables the JDT.LS inlay-hint and
references/implementations CodeLens settings. All are additive providers; the exact
JDT.LS command ids are guarded.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…yword colors

- Find/Peek References (and go-to-definition/implementation/type-definition) now
  create in-memory models for the referenced files, so the peek shows a real code
  preview instead of only file/line/column.
- Flush the pending debounced didChange before a completion request, so JDT.LS sees
  the just-typed text on the first Ctrl+Space (previously the first invocation
  completed against stale content and only the second worked).
- Revert the forced semanticHighlighting flag: JDT.LS emits keyword/modifier
  semantic tokens the vs-dark-based themes don't style, which left Java keywords
  uncolored. The semantic-tokens provider stays registered (inert until a theme opts
  in) so basic Monarch keyword coloring is restored.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…e after rename

Root cause of "no quick-fixes / no Implement Methods / Generate toString does nothing":
- We advertised the *PromptSupport extended capabilities, so JDT.LS returned source
  actions (generate toString/constructors/accessors, override/implement, organize
  imports) as client-side "java.action.*Prompt" commands that the vscode-java
  extension implements but we don't — and the server commands we tried to call
  (checkToStringStatus/generateToString/…) don't exist on JDT.LS. Dropping those
  flags makes JDT.LS return the same actions as resolvable WorkspaceEdits (all
  members), which applyCodeAction resolves and applies directly.
- Code-action requests sent diagnostics reconstructed from Monaco markers, which lose
  the LSP code/data JDT.LS matches quick-fixes against. We now keep the original
  published diagnostics per file and send the ones overlapping the request range, so
  "Add unimplemented methods", "Create field", etc. appear.

Also: the Projects view ignored file rename/move events, so after a class rename the
tree still showed the old file. It now reloads on platform.files.renamed/moved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n completion)

Renaming a public type (F2) had two defects:
- When JDT.LS ordered the RenameFile before the text edit, the edit was keyed by the
  new URI; we wrote the old content (old type name) into the new file, producing
  "The public type X must be defined in its own file". Edits are now re-attributed to
  the on-disk (old) URI before applying, so the new file gets the new type name.
- After renaming on disk we never told JDT.LS, so it kept validating stale state until
  a page refresh and kept suggesting the old type name in completion. We now send
  textDocument/didClose for the renamed-away file and workspace/didChangeWatchedFiles
  (Deleted old / Created new / Changed edited) so the server re-indexes immediately —
  clearing the stale diagnostic and dropping the old name from completion.

This also removes the exception/fallback path that made the first Enter occasionally
apply only the in-editor edit without renaming the file.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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