# lsp4j turns the Language Server Protocol into a Java API

> Eclipse LSP4J is a Java implementation of the Language Server Protocol and the Debug Adapter Protocol, published under EPL-2.0 OR BSD-3-Clause. It saves you from hand mapping JSON-RPC types, and it charges you for that convenience with frequent breaking API changes whenever the specification moves.

**eclipse-lsp4j/lsp4j** — A Java implementation of the language server protocol intended to be consumed by tools and language servers implemented in Java.

- Repository: https://github.com/eclipse-lsp4j/lsp4j
- Website: https://eclipse.org/lsp4j
- Stars: 731 · Forks: 160
- Language: Java
- License: NOASSERTION
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/eclipse-lsp4j-lsp4j

## A protocol binding, not a language server

The repository description is precise about the scope: LSP4J is a Java implementation of the language server protocol intended to be consumed by tools and language servers implemented in Java. That last clause is the whole point. The protocol itself is a specification with a JSON-RPC transport, and the specification is written with TypeScript types in mind. LSP4J takes those types and gives you Java classes for them, along with the plumbing to launch a server or connect to one as a client. The README calls it a Java binding for the Language Server Protocol and the Debug Adapter Protocol, so both protocols are covered in the same project, which matters for tools that do completion and debugging in one session. The audience is therefore two groups: developers writing an editor plugin or an IDE integration in Java that must talk to language servers, and developers writing a language server itself in Java. What you get is the type layer and the JSON-RPC machinery. What you do not get is a server framework, a completion engine or a parser, and the documentation entry points make that division clear, pointing to a Getting Started page and a Core Concepts page on JSON-RPC rather than to a list of ready made features.

## Six bundles that separate transport, types and codegen

The top level directory listing shows how the project is factored, and the split matters when you choose a dependency. There are bundles for the main protocol, org.eclipse.lsp4j, one for the debug side, org.eclipse.lsp4j.debug, and the JSON-RPC layer in org.eclipse.lsp4j.jsonrpc with a matching org.eclipse.lsp4j.jsonrpc.debug. A separate org.eclipse.lsp4j.generator bundle is the code generator, and the one that produces the protocol classes in the first place, which is the part you normally do not depend on at runtime. Then there is org.eclipse.lsp4j.websocket.jakarta, a WebSocket transport tied to the Jakarta APIs, which is what you reach for when the two processes talk over a socket rather than over standard input and output. The API policy section explains why the version number is shared. All bundles within LSP4J share a version number to simplify version management, both for the project itself and for consumers, and the version increment for any bundle is the largest increment required by semantic versioning of any of the bundles. That means you cannot upgrade one artifact independently, and the practical effect is that a change in the generator or the JSON-RPC layer can bump the version of the whole set you depend on.

## Getting the artifacts, and the signature problem you inherit

There is no install script, because this is a Java library consumed through a build tool. The README points at three distribution channels. Maven Central is the ordinary route, with the artifacts published under the org.eclipse.lsp4j group path. The Eclipse p2 update sites carry releases, milestones and nightly builds, at the download.eclipse.org locations for releases, milestones and the main branch builds. Snapshots are deployed during the build to the Sonatype OSS snapshot repository. Whichever channel you pick, one detail will bite you if you are shading or repackaging. The Maven repositories, the p2 update sites and the snapshots all contain signed jars, and if you plan to simply add them to your own jar you need to remove or exclude those signatures, or update or override them. The README links the two Stack Overflow answers that describe how, which is a small signal of how often this trips people up. The other thing to notice is that the release and nightly channels carry a japicmp report against the last released version, and the p2 update sites have done so since 0.13.0. In other words, the API diff is published alongside the artifact, which is the mechanism to plan an upgrade.

## The version table is the contract with your peer

The most useful page in this README is the pair of tables that map every LSP4J version to the protocol revision it implements. LSP4J 1.0 and the next release target LSP 3.18.0, with the addition of the SymbolTag proposal, and the README notes that the 3.18 specification is not finalized yet. The 0.24 and 0.23 lines target LSP 3.17.0, as do 0.22 down to 0.13, with two documented exceptions, since 0.14 excludes Notebook support and WorkspaceSymbol.data, and 0.13 excludes Notebook support plus some specification changes that landed after 3.17 was published as final. Older lines step back further, with 0.12 and 0.11 on LSP 3.16.0, 0.10 on 3.16 as well, 0.9 on 3.15 without Progress, 0.7 and 0.8 on 3.14, and the earliest releases going back to LSP 2.1. The Debug Adapter table runs in parallel: 1.0 and the next release map to DAP 1.70.0, 0.24 to 1.69.0, 0.23 to 1.65.0, down to 0.4 on DAP 1.25.0, and LSP4J before 0.4.0 did not support DAP at all. This matters at the point where a client and a server meet. If the editor expects a protocol revision your LSP4J release does not implement, the symptom is a request that never arrives or a field the other side does not read, so the table is the first thing to check when a pair refuses to talk.

## Semantic versioning and the breaking change you cannot avoid

The API policy section is unusually candid, and it is the part to read before choosing a version. LSP4J uses semantic versioning, with the version increment determined by japicmp. Breaking API changes are published in the CHANGELOG, every release and continuous build runs the japicmp tool wrapped in runjapicmp.sh, the generated reports for releases and the development branch are linked from the CHANGELOG, and the GitHub Actions builds save the same report as an artifact for each pull request and commit. Before 1.0, semantic versioning was not used, which explains the long stretch of 0.x releases and the leap from 0.24.0 to 1.0.0. The reason a new specification version forces a major bump is spelled out with an example. In JSON-RPC plus TypeScript, an additional type is not a breaking change, but in Java with LSP4J it often is, and the case given is that in LSP 3.18, Diagnostic.message changed from string to string or MarkupContent, represented in Java as a change from String to Either<String, MarkupContent>, which is an API breaking change and would necessitate a major version bump. For a consumer, that means the type system is where the specification churn lands, and the japicmp reports are how you find out before compiling rather than after.

## Where the binding stops being worth it

There are situations where pulling in LSP4J is the wrong decision. The first is scale. If your tool needs one request and one response, the protocol is JSON-RPC over a stream, and adding a Gradle dependency plus a generated type library to avoid writing a few small data classes is a poor trade. The second is tolerance for churn. The project states plainly that new versions of the LSP and DAP specifications may lead to breaking API changes because of the mapping of TypeScript types to Java types, and that maintaining binary compatibility is particularly difficult when a protocol change allows a field to take additional types. A tool that must ship one binary and interoperate with many server versions has to pin carefully and test across the range in those tables. The third is the pre-1.0 history itself, where semantic versioning was not applied, so an application that upgrades across the 0.24 to 1.0 boundary is looking at the largest API reshuffle in the project's history. The alternative approach is not another Java library but a different design: keep the wire format as plain JSON-RPC and map it into your own domain objects with a thin layer of your own, which leaves the protocol surface under your control and makes specification changes a local edit. The cost is that you own the type mapping for every feature you support.

## Conclusion

lsp4j is the sensible choice for a Java tool that speaks the Language Server Protocol or the Debug Adapter Protocol today, because the generated type layer and the published API reports remove most of the guesswork from a protocol whose types keep moving. It is the wrong tool if your client only needs one or two simple requests, since hand written JSON-RPC over a WebSocket is less code than a Gradle dependency, or if you cannot absorb major version bumps, since the project states that new specification versions may force API breaking changes. Before you commit, read the Supported LSP Versions and Supported DAP Versions tables in the README against the protocol revision your peer implements, and check the japicmp report for your upgrade, because the last push was on 2026-10-19 and the 1.0 line already tracks LSP 3.18.0.

## FAQ

### Which LSP version does lsp4j implement?

LSP4J 1.0 and the next release target LSP 3.18.0 plus the SymbolTag proposal, while the 0.24 and 0.23 lines target LSP 3.17.0. The README keeps a full table mapping older versions back to LSP 2.1.

### How do I get lsp4j artifacts?

They are published to Maven Central under the org.eclipse.lsp4j group, and the Eclipse p2 update sites carry releases, milestones and nightly builds. Snapshots are deployed to the Sonatype OSS snapshot repository during the build.

### What licence is lsp4j published under?

Two, as an SPDX-License-Identifier of EPL-2.0 OR BSD-3-Clause. The Eclipse Public License v2.0 and the Eclipse Distribution License v1.0, which the README describes as a BSD-3-clause license.

## Sources

- [eclipse-lsp4j/lsp4j on GitHub](https://github.com/eclipse-lsp4j/lsp4j)
- [Issues](https://github.com/eclipse-lsp4j/lsp4j/issues)
- [Project website](https://eclipse.org/lsp4j)
- [README](https://github.com/eclipse-lsp4j/lsp4j/blob/main/README.md)
- [Releases](https://github.com/eclipse-lsp4j/lsp4j/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/eclipse-lsp4j-lsp4j
