Contributions are extremely welcome, no matter how big or small. If you have any questions or suggestions we are happy to hear them.
- Project Structure
- Implementing language features for
application.properties
- Implementing language features for Java files
- Development Setup
- Debugging
vscode-quarkus extends vscode-microprofile to benefit with
MicroProfile/Quarkus properties
and Java
files support.
See Contributing guide for more information.
For vscode-quarkus to work, it relies on the
MicroProfile language server
and the
MicroProfile jdt.ls extension
. The MicroProfile language server is responsible for providing
LSP language features
to VSCode, while the MicroProfile jdt.ls extension is responsible
for functionalities like listening
to Java classpath changes and generating config setting metadata for
the application.properties
file.
The reason why
vscode-java
is required for vscode-quarkus to work, is because vscode-java
starts the jdt.ls
language server, which is required to run the MicroProfile jdt.ls extension.
Note: The MicroProfile language server currently provides language features for both *.properties
and *.java
files.
Please see quarkus-ls#215.
The image above represents communication between the three components. As the image implies, the MicroProfile language server cannot directly communicate with the MicroProfile jdt.ls extension and vice-versa. They must communicate via vscode-quarkus.
Here is an example of how the components work together for
application.properties
completion:
Step 1. A Quarkus project is opened in VSCode, and completion has been
invoked inside the application.properties
file, which sends a
textDocument/completion
request to the MicroProfile language server.
Step 2. MicroProfile language server checks its cache if completion options exist.
- If it exists the MicroProfile language server sends them to VSCode
as the response to the
textDocument/completion
request. Communication is complete, and does not proceed to Step 3 and onwards. - If it does not exist, the MicroProfile language server sends a
custom request,
microprofile/projectInfo
to vscode-quarkus. Proceed to Step 3.
Step 3. vscode-quarkus receives the microprofile/projectInfo
request,
and delegates it to the MicroProfile jdt.ls extension.
Step 4. The MicroProfile jdt.ls extension receives the command, determines project information (project URI, configuration properties, hints etc.) about the currently opened (MicroProfile or Quarkus) project and returns the information to vscode-quarkus. The project information is then sent to the MicroProfile language server
Step 5. vscode-quarkus receives the project information and sends it to the MicroProfile language server.
Step 6. MicroProfile language server receives the information, adds it
to its cache, and returns the completion options stored in the
project information as the response to the textDocument/completion
request.
When an application.properties
file sends a request (e.g. textDocument/completion) to the
MicroProfile language server, the requests are accepted in
ApplicationPropertiesTextDocumentService#completion.
This class receives LSP requests for application.properties
files.
Properties collected by the MicroProfile jdt.ls extension are cached to keep response times fast. Collecting properties will not be done unless absolutely necessary (ie, if cache doesn't exist, if project dependencies change).
When the completion is triggered,
the MicroProfile LS checks the properties cache for the given application.properties
file.
If the cache does not exist, it calls the microprofile/projectInfo
request to call the JDT LS Extension projectInfo delegate command handler which
uses the
properties manager
that collects MicroProfile and Quarkus properties for the given Java project.
This manager is extensible by the
org.eclipse.lsp4mp.jdt.core.propertiesProviders
extension point:
- org.eclipse.lsp4mp.jdt.core defines properties provider for MicroProfile.
- com.redhat.microprofile.jdt.quarkus defines properties provider for Quarkus.
Here are some providers and the annotation(s) they scan for:
Class | Annotations |
---|---|
MicroProfileConfigPropertyProvider | org.eclipse.microprofile.config.inject.ConfigProperty |
MicroProfileRegisterRestClientProvider | org.eclipse.microprofile.rest.client.inject.RegisterRestClient |
QuarkusConfigPropertiesProvider | io.quarkus.arc.config.ConfigProperties |
QuarkusConfigRootProvider | io.quarkus.runtime.annotations.ConfigRoot |
QuarkusKubernetesProvider | io.dekorate.kubernetes.annotation.KubernetesApplication io.dekorate.openshift.annotation.OpenshiftApplication io.dekorate.s2i.annotation.S2iBuild io.dekorate.docker.annotation.DockerBuild |
Some Quarkus properties like quarkus.hibernate-orm.dialect
are not defined in JARs belonging
to the current Quarkus project's classpath. Some Quarkus classpath JARs have deployment JARs.
Generally speaking, deployment JARs are not present in the project's classpath.
If classpath JARs have a deployment JAR, it will be defined in the
META-INF/quarkus-extension.properties
file of the classpath JAR.
For example, the quarkus-hibernate-orm-1.2.0.Final.jar
has a deployment JAR with
an artifactId of quarkus-hibernate-orm-deployment
:
The MicroProfile jdt.ls extension creates a "fake" Java project with the deployment JARs in its classpath and performs a scan for properties for this fake project, in order to retreive the desired properties.
To make things more concrete:
Consider a Quarkus project with a pom.xml
with this dependency:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
Properties like quarkus.hibernate-orm.dialect
and quarkus.hibernate-orm.sql-load-script
are
not defined (no classes annotated with @ConfigRoot
) in the quarkus-hibernate-orm*.jar
JAR.
Those properties are located in its deployment JAR: quarkus-hibernate-orm-deployment*.jar
.
The deployment jar is listed in META-INF/quarkus-extension.properties
from the quarkus-hibernate-orm*.jar
as a property:
deployment-artifact=io.quarkus\:quarkus-hibernate-orm-deployment\:1.2.0.Final
Note that in most cases, a Quarkus project would not have deployment JARs listed as dependencies in the project's
pom.xml
, which is why the deployment JARs would not be in the project's classpath.
Therefore in order to scan for the properties in the deployment JAR, under the hood, the MicroProfile jdt.ls extension delegates the resolution (i.e. download) of those deployment jars to Maven, regardless of the user project's build system.
In conclusion, a project depending on:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm</artifactId>
</dependency>
will generate the hibernate properties coming from the deployment JAR, like:
quarkus.hibernate-orm.dialect
quarkus.hibernate-orm.sql-load-script
even if the deployment JAR itself, was not declared in the Quarkus project's pom.xml
like so:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-hibernate-orm-deployment</artifactId>
</dependency>
When a Java file sends a request (e.g. textDocument/codeLens
) to the
MicroProfile language server, the requests are accepted in
JavaTextDocumentService#completion.
This class receives LSP requests for Java files.
The textDocument/codeLens
, textDocument/publishDiagnostics
, textDocument/hover
requests are delegated to
MicroProfileDelegateCommandHandlerForJava
which creates the lsp4j.Hover
,
lsp4j.CodeLens
and lsp4j.PublishDiagnosticsParams
instances for hover, codelens and diagnostics respectively.
Just like how application.properties
properties are extensible via extension point, Java codeLens, diagnostics and
hover are also extensible via extension point.
These Java features are extensible by the
org.eclipse.lsp4mp.jdt.core.javaFeatureParticipants
extension point:
- org.eclipse.lsp4mp.jdt.core defines Java feature participants for MicroProfile.
- com.redhat.microprofile.jdt.quarkus defines Java feature participants for Quarkus.
Here are some examples of the leveraging the extension point to provide Java codeLens, diagnostics and hover:
Java Feature | Participant |
---|---|
MicroProfile Health diagnostics | MicroProfileHealthDiagnosticsParticipant |
MicroProfile Rest Client diagnostics | MicroProfileRestClientDiagnosticsParticipant |
MicroProfile Rest Client codeLens | MicroProfileRestClientCodeLensParticipant |
JAX-RS codelens | JaxRsCodeLensParticipant |
MicroProfile @ConfigProperty name hover |
MicroProfileConfigHoverParticipant |
Step 1. Fork and clone this repository
Step 2. Fork and clone this repository, which contains the MicroProfile jdt.ls extension and MicroProfile language server
Note: Ensure that the cloned repositories are under the same parent directory:
YOUR_FOLDER/
├──── vscode-quarkus/
├──── quarkus-ls/
Step 3. Navigate into vscode-quarkus/
$ cd vscode-quarkus/
Step 4. Install npm dependencies
$ npm install
Step 5. Build the MicroProfile language server and MicroProfile jdt.ls extension
$ npm run build
This script does two things.
- Builds the MicroProfile language server and places the jar in
vscode-quarkus/server/
. - Builds the MicroProfile jdt.ls extension and places the jar in
vscode-quarkus/jars/
.
In addition to npm run build
, there are two more build scripts:
npm run build-server
only builds the Quarkus language server and places the jar in vscode-quarkus/server/
.
npm run build-ext
only builds the Quarkus jdt.ls extension and places the jar in vscode-quarkus/jars/
.
Step 1. Open vscode-quarkus/
in VSCode.
Step 2. Open the Debugging tab, select and run "Launch Extension (vscode-quarkus)" at the top left.
To run vscode-quarkus along with changes within vscode-microprofile, select run "Run Extension with MicroProfile sources" at the top left.
This assumes both projects are located within the same parent folder.
There are two types of tests written for vscode-quarkus: the integration tests and the UI tests.
Run integration tests: npm test
Run UI tests: npm run test-ui
Run both (integration tests first, UI tests second): npm run test-all
These tests are located located in the vscodeTest/
and vscodeUiTest/
directories
respectively:
vscode-quarkus/
├──── src/
├──── test/
├──── vscodeTest/
├──── vscodeUiTest/
To debug the integration tests, open the VS Code Debugging tab and select the "Extension Tests (vscode-quarkus)" at the top left:
To debug the UI tests, open the VS Code Debugging tab and select the "VS Code UI Extension Tests (vscode-quarkus)" at the top left:
Its very important to not disturb your machine when running the UI tests, or else the test functions will not run properly.
Note for running UI tests of macOS: Due to an issue for an upstream UI testing library: nut-tree/nut.js#98 (issue), UI tests on macOS work as long as Node version 12.12 or lower is used.
Additionally, you may also need to allow your terminal application to control your computer like so:
In an IDE of your choice, set the debugger configuration to connect to localhost, port 1064.
If using VSCode, open quarkus-ls/microprofile.ls/
in VSCode. The proper
debugger configurations are already defined in .vscode/
.
There should be a "Debug (Attach) - Remote (microprofile.ls)" option
at the top left of the Debugging tab.
The JVM arguments used to start the MicroProfile language server are specified here.
Only Eclipse can be used to debug the MicroProfile jdt.ls extension.
Step 1. Open the jdt.ls source code in a new workspace in Eclipse by following the setup steps in the jdt.ls GitHub repository here.
Step 2. In the same workspace, import the projects from
quarkus-ls/microprofile.jdt/
.
Step 3. In the Debug dropdown menu, open "Debug Configurations...".
Step 4. Create a new "Remote Java Application" launch configuration. Set the following settings and click "Apply":
Project: com.redhat.microprofile.jdt.core
Connection Type: Standard (Socket Attach)
Host: localhost
Port: 1044
By contributing to this project you agree to the Developer Certificate of Origin (DCO). This document was created by the Linux Kernel community and is a simple statement that you, as a contributor, have the legal right to make the contribution. See the DCO file for details.