Pro-Grade Java Development in Claude Code - Beyond Grep with LSP
In the world of AI driven coding, context is currency. Most developers run Claude Code (CC) in its "out-of-the-box" state, relying on the agent's internal grep tool to navigate codebases. While Claude is brilliant, grep is a blunt instrument.
To transform CC into a true "Senior Pair Programmer," you need to bridge the gap between Pattern Matching and Semantic Understanding. This is where the Language Server Protocol (LSP) and Eclipse JDT.LS come in.
🧠 Why the "LLM is Smart Enough" Argument Fails
A common misconception is that the LLM's reasoning capabilities negate the need for local tooling. This is incorrect for two critical reasons:
- The Noise Tax: When you ask CC to "find all usages of a method," grep returns every string match, including Javadocs, logs, and commented-out code. This "noise" is sent to the LLM, consuming thousands of unnecessary tokens and increasing the risk of the model losing the "signal" in the mess.
- The Latency Gap: A keyword search followed by LLM filtering takes 10–60 seconds. An LSP query (like textDocument/references) returns the exact AST (Abstract Syntax Tree) coordinates in milliseconds.
The Semantic Advantage
While grep sees text, Eclipse JDT LS sees structure. It understands the difference between a method call, a variable declaration, and a string literal—allowing CC to operate with surgical precision.
🎓 The Expert Setup: CC + DevContainers
For a reproducible high-performance environment, you should manage your LSP via a DevContainer. (And if you have been following me from my earlier blogs, you would know that I am an advocate of running CC in isolated environments for security reasons, and I love and leverage Docker for this.) This ensures that jdtls and its dependencies (JDK 17/21) are isolated from your host machine.
1. Setting up Java LSP for CC in DevContainer
-
The Dockerfile: Minimal reference implementation:
---- - Also, do feel free to check out my reference implementation in the DhanHQ-java repository for the exact docker-compose and settings.json configurations.
2. The Environment Variable
As of April 2026, the LSP tool is enabled via an undocumented feature flag (It was discovered via GitHub Issue #15619 and that issue still is in Open status). This is the "secret sauce" for power users.
- Flag: ENABLE_LSP_TOOL=1
- Ensure that in your `.claude/settings.json` its `env` attributes is set with `"ENABLE_LSP_TOOL": "1"`.
- I personally have `export ENABLE_LSP_TOOL=1` done to my shell profile via my Dockerfile/docker-compose.yaml file for my CC-Dev-Container.
3. Installing LSP Plugin in CC
Post Java LSP installation and CC configuration set-up in its `settings.json`, start CC and run command `/plugins` to install jdtls-lsp from Claude's Plugins Official marketplace and then do run `/reload-plugins` for the installed plugin to kick-in.
🔬Testing and Trouble-shooting
If you have an `OrderEndpoint.java` class in your java project, run a prompt like one of the below:
- Find all references to OrderEndpoint
- Get me the definition of OrderEndpoint
- List all functions in OrderEndpoint
- Find the OrderEndpoint class in the project
- Where is placeOrder defined
All of the above should hit LSP and respond quickly in milliseconds. If it is taking time, it is likely that it is using `grep` functionality to do keyword search and send the result to your LLM with lot of noise including matches in imports and comments taking anywhere between 10-60 seconds and burning a lot of your tokens.
Known Constraints & Troubleshooting
- Plugin Reloading: Always run `/reload-plugins` after installing the jdtls-lsp plugin from the official-marketplace to ensure the bridge is established.
- Memory Overhead: jdt.ls is a headless Eclipse instance. Ensure your container has at least 4GB of RAM. Insufficient memory will cause the LSP to crash, and CC will silently fall back to grep.
- Index Warm-up: On massive projects, give the LSP 30-60 seconds to index the classpath before expecting instant results.
⚡ Performance Benchmark: LSP vs. Grep
When testing your setup, look for these "Expert-Level" behaviors:
Prompt
Without LSP (Grep)
With LSP (jdt.ls)
Find definition of processOrder
Scans whole project; may pick wrong file
Jumps directly to source line
List class methods in MyConnection
Returns method names + Javadoc noise
Returns a clean, structured symbol list
Find references of OrderEndpoint
Returns string matches (Slow/Expensive)
Returns actual code usages (Fast/Cheap)
By integrating Java LSP, you aren't just adding a tool; you are upgrading Claude's "vision." You save money on tokens, reduce latency, and allow the LLM to focus on logic rather than data filtering.