Eclipse JDT Language Server Project

The Eclipse JDT Language Server (a.k.a. jdt.ls) is an open source Java language specific implementation of the Language Server Protocol, incubating at the Eclipse Foundation.

From the Language Server Protocol website:

The Language Server Protocol is used between a tool (the client) and a language smartness provider (the server) to integrate features like auto complete, goto definition, find all references and alike into the tool.

The Language Server Protocol, an open source project under the MIT License, was originally developed by Microsoft while integrating OmniSharp and the TypeScript Server into the Visual Studio Code editor with the goal to simplify new programming language integration into the editor. It was later developed independently and is now completely editor/IDE agnostic. The protocol specifies the messages must be exchanged in the JSON RPC v2.0 format, but doesn't mandate a specific transport mechanism or how the server should be implemented.

jdt.ls is written in Java and is basically a small, headless Eclipse JDT distribution, providing comprehensive Java support to a wide array of clients.

The server part is itself built with the Eclipse LSP4J framework.

How does it work?

Basically, any editor/IDE (the client) compatible with the Language Server Protocol can start jdt.ls, which will initialize an Eclipse IDE workspace under the hood and will then import all the Java projects found in the current working directory of the client.

The client will then submit requests to the language server, as the user interacts with the Java files:

Sequence Diagram

The server allows the client to provide users with:

  • As-you-type reporting of parsing and compilation errors
  • Code completion
  • Code navigation
  • Code lens (references)
  • Code formatting
  • Code outline
  • Code actions (quick fixes)
  • Highlights
  • Javadoc hovers
  • Type search

Build types

The server looks for project/build descriptors in order to correctly configure the Java support (compiler level, classpath). The project import mechanism will lookup build descriptors in the following order:

  1. Search for *.gradle files: if a Gradle project is detected, the import will be delegated to Eclipse Buildship.
  2. Search for pom.xml files: if a Maven project is detected, the import will be delegated to Eclipse m2e.
  3. Search for Eclipse IDE .project files: the projects will be imported as simple Eclipse IDE projects.

Depending on the project type, some specific behavior can be expected:

  • Gradle
    • sources of dependencies are automatically downloaded.
    • changes to build.gradle dependencies require an explicit project configuration update.
    • please note that Android projects are not supported at the moment.
  • Maven
    • sources of dependencies are automatically downloaded.
    • Maven errors are reported on the pom.xml.
    • Changes to pom.xml dependencies automatically updates the projects classpath.
  • Eclipse IDE
    • please note that WTP based projects can not be configured properly, as the JLS is missing all the WTP plugins

Standalone files

Getting informations on a single java file, out of any project context is a bit tricky. The Java tooling has no information about what would be the classpath required to compile the file. So, for that specific use case, type checking errors are silenced, as it's not useful to let clients displays dozens of compilation errors. However the server can still analyze the file for syntax errors, or provide assistance for at least the default JDK classes.

Supported Language Server Protocol features

The current implementation of jdt.ls supports most of Language Server Protocol v3, as described below:

Message

Supported

Initialize

shutdown

exit

$/cancelRequest

window/showMessage

window/showMessageRequest

window/logMessage

telemetry/event

window/didChangeConfiguration

window/didChangeWatchedFiles

textDocument/publishDiagnostics

textDocument/didChange

textDocument/didClose

textDocument/didOpen

textDocument/didSave

textDocument/completion

completionItem/resolve

textDocument/hover

textDocument/signatureHelp

textDocument/references

textDocument/documentHighlight

textDocument/documentSymbol

textDocument/formatting

textDocument/rangeFormatting

textDocument/onTypeFormatting

textDocument/definition

textDocument/codeAction

textDocument/codeLens

codeLens/resolve

textDocument/documentLink

documentLink/resolve

textDocument/rename

But jdt.ls also enhances the default Language Server Protocol by adding specific messages:

Message

Description

⬅ language/status

The status notification is sent to the client to request the client to display a particular message in the user interface. This is typically used during server startup

⬅ language/actionableNotification

An actionable notification is sent to the client to display a particular message in the user interface with possible commands to execute. The commands must be implemented on the client side.

↩ java/classFileContents

The client requests the contents of a .class file URI, the server returns the source contents, if available.

➡ java/projectConfigurationUpdate

The client requests a project configuration update, i.e. to synchronize the jdt.ls internal project model with the project build descriptor (Maven or Gradle)

Integrating with jdt.ls

Installation

First of all, make sure you have a JDK 8 to run the server.

The latest jdt.ls compressed binary can be downloaded from the download area. There's a stable link to the latest build:

http://download.eclipse.org/jdtls/snapshots/jdt-language-server-latest.tar.gz

You then need to decompress the server tar.gz to some location of your choice.

Setting up the connections

jdt.ls supports sockets, named pipes, and standard streams of the server process to communicate with the client. A client can communicate its preferred connection methods by setting up environment variables.

  • The standard streams(stdin, stdout) of the server process are used by default.
  • To use name pipes set the following environment variables before starting the server.
STDIN_PIPE_NAME --> where client reads from
STDOUT_PIPE_NAME --> where client writes to
  • To use plain sockets set the following environment variables before starting the server.
STDIN_PORT --> client reads
STDOUT_PORT --> client writes to

Optionally you can set host values for socket connections.

STDIN_HOST
STDOUT_HOST

For socket and named pipes the client is expected to create the connections and wait for server the connect.

Running the server

Once the connection environments have been set, jdt.ls can be run by executing:

/path/to/jdk/java -Declipse.application=org.eclipse.jdt.ls.core.id1 / 
    -Dosgi.bundles.defaultStartLevel=4 /
    -Declipse.product=org.eclipse.jdt.ls.core.product /
    -noverify -Xmx1G -XX:+UseG1GC -XX:+UseStringDeduplication /
    -jar /path/to/server/plugins/org.eclipse.equinox.launcher_<version>.jar / 
    -configuration /path/to/server/config_mac /
    -data /path/to/some/workspace/
  • You need to replace server/plugins/org.eclipse.equinox.launcher_<version>.jar with the actual name of the org.eclipse.equinox.launcher jar
  • The configuration flag can point to either:
    • config_win, for Windows
    • config_mac, for MacOS
    • config_linux, for Linux
  • The data flag value should be the absolute path to the working directory of the server. This should be different from the path of the user's project files (which is sent during the initialize handshake).

Known clients

The Developer Tooling community largely embraced the Language Server Protocol paradigm and several initiatives were started, aiming at integrating jdt.ls in other editors/IDEs:

Visual Studio Code and the Language Support for Java extension

The Red Hat team, participating in the jdt.ls project, is also actively developing the Language Support for Java extension for Visual Studio Code (a.k.a. vscode-java, as a way to validate the jdt.ls implementation. This extension is fairly popular, in the top 20 of the most installed extensions for VS Code.

You can install it from the Visual Studio Marketplace, or from the command palette:

ext install java

The following animation gives you an overview of the Java support in VS Code:

java support vs code

During Devoxx.us 2017, the Red Hat team presented jdt.ls and how to develop a Spring Boot based application with VS Code:

Conclusion

The Eclipse JDT Language Server is already a really exciting piece of technology, but we want to make it even better. Our goal is to provide comprehensive refactoring capabilities, as well as a Java debugger. So stay tuned!

Both the jdt.ls and vscode-java are developed under the open source Eclipse Public License v1.0. All contributions are welcome, whether it’s code, feedback, bug reports. Please do so under any of these GitHub repositories:

About the Authors

Fred Bricon

Fred Bricon
Red Hat

Gorkem Ercan

Gorkem Ercan
Red Hat